In this script, simulate 5 different datasets based on N value. Each will be a GLV model of 50 subjects over 10 time points with the same starting correlation matrix. N values are 10, 20, 50, 75 and 100 taxa

1. Load Library


library(tidyverse)
library(igraph)
library(NBZIMM)
library(SpiecEasi)
library(LIMON)
library(here)
library(lme4)
library(Matrix)
library(tscount)
library(patchwork)
library(MASS)
library(matrixcalc)
library(gridExtra)
library(devtools)
library(miaSim)
library(reshape2)

2. Simulate N = 10


Simulate Counts
Simulate GLV for 10 species, 50 individuals, 10 time points, dense n

# Set seed
set.seed(12345)

# Step 1 Run GLV for n number of subject and timepoints
###############################################################################

# Generate interactions from uniform distribution
A_uniform <- randomA(
    n_species = 10,
    diagonal = -1.0,
    connectance = 0.9)

# Create an empty list to store the count tables for each subject
count_tables <- list()


# Loop through subjects and generate count tables for each
for (i in 1:50) {
  # Set the seed for each subject
  set.seed(12345 + i)  
 # Generalized Lotka-Volterra (gLV)
  tse_glv <- simulateGLV(n_species = 10,
                       A = A_uniform,
                       t_start = 0, 
                       t_store = 10,
                       stochastic = FALSE,
                       norm = FALSE,
                       error_variance = 0.01)
  
  # Get the count table
  sim_data <- tse_glv@assays@data@listData[["counts"]]
  
  # Store the count table in the list
  count_tables[[i]] <- t(sim_data)
}

# Step 2 - Merge together
###############################################################################
# Combine all count tables into one data frame
combined_count_table <- do.call(rbind, count_tables)

# Rename the rownames based on the count table number
rownames(combined_count_table) <- paste0("Sbj", rep(1:50, each = nrow(count_tables[[1]])), "_Time", 1:10)

Create Fake Metadata
1. Sex (M or F, 50/50 Ratio) 2. Age - sample from between 18 and 45 3. BMI - sample between 18 and 35

Make Metadata and merge with the count data

# Df 1 is Metadata
########################################################
meta_data <-  expand.grid(Time = 1:10,ID = 1:50)
rownames(meta_data) <- rownames(combined_count_table)
# Set seed
set.seed(12345)
meta_data$Sex <- rep(c(0, 1), each = 50)
# Set seed
set.seed(12345)
meta_data$Age <- rep(sample(18:45, 50, replace = TRUE), each = 10)
# Set seed
set.seed(12345)
meta_data$BMI <- rep(sample(18:35, 50, replace = TRUE), each = 10)

# Center the continuous variables
meta_data$Age <- meta_data$Age - mean(meta_data$Age)
meta_data$BMI <- meta_data$BMI - mean(meta_data$BMI)


# Df 2 is Metadata merged with Counts
########################################################
#Round off and increase
combined_count_table <- as.data.frame(combined_count_table + abs(min(combined_count_table)))
combined_count_table <- (combined_count_table)*10
meta_counts <- base::merge(meta_data, combined_count_table, by ="row.names", all = TRUE)
meta_counts <- column_to_rownames(meta_counts, "Row.names")

Add in biological covariates

# Set seed
set.seed(12345)
# Addin covariates
########################################################################################
# Set up new dataframe
Long_data_new <- meta_counts


# Loop running the LM to get new variables with error that has a range of values
# Taxa 7 - 8 will have Sex effect
for (i in 12:13) {
  error <- rnorm(nrow(Long_data_new), mean = 1, sd = 0.6)
  Long_data_new[, i] <- Long_data_new[, i] + 8 * Long_data_new$Sex + error
}

# round the counts to bring them back up to 0
########################################################################################

# Add the minimum value to bring everything up to at least 0
count_table1 <- Long_data_new[,6:15]


# scale to positive and make larger
count_table1 <- count_table1 + abs(min(count_table1))
count_table1 <- round(count_table1*10)

#change Long_data_new
Long_data_new[,6:15] <- count_table1

Now Add in 0s

# Set up new dataframe
predata_0 <- count_table1

# Add the 0s back in
########################################################################################


# Step 1: Calculate total counts for each column
total_counts <- colSums(predata_0)


# Step 2: Create probability gradient
gradient <- seq(0.5, 0.2, length.out = ncol(predata_0))

# Step 3: Make the probability gradient inverse to total counts (ie higher total value, lower proportion of 0s)
total_counts <- total_counts[order(total_counts)]
gradient <- gradient[order(-gradient)]

# Step 4 & 5: Generate random numbers and set counts to 0 based on probability gradient

for (i in seq_along(total_counts)) {
  prob <- gradient[i]
  # Calculate number of 0s to add based on probability
  num_zeros <- sum(runif(nrow(predata_0)) <= prob)
  # Randomly select rows to set to 0
  # Set seed
  set.seed(12345+i)
  rows_to_zero <- sample(nrow(predata_0), num_zeros)
  # Set counts to 0
  predata_0[rows_to_zero, i] <- 0
}

# merge with metadata for plotting
zero_data1 <- merge(meta_data, predata_0, by = 0)
zero_data1 <- column_to_rownames(zero_data1, "Row.names")
#round the counts
zero_data1[,6:15] <- round(zero_data1[,6:15])

Graphs to Check

# Individual Species Plots
########################################################
# Pivot to long data
count_long <- tidyr::pivot_longer(zero_data1, cols = starts_with("sp"), names_to = "Species")

# Plot the data
count_long %>%
  ggplot(aes(x = Time, y = value, colour = as.factor(ID),
             group = as.factor(ID), linetype = as.factor(ID))) +
  geom_line() + 
  geom_point() +
  geom_jitter() +
  ylab("Count") +
  labs(linetype = "ID", color = "ID") +
  facet_wrap(~ Species) +  # Create a panel for each species
  theme(legend.position = "none") +
  ggtitle("Time Series of N=10, 0s")



# Distribution of counts
########################################################
hist(as.matrix(zero_data1[,6:15]), breaks = 100, main = "Distribution of GLV Data", xlab = "Counts")


# Correlation matrix
cor_raw1 <- cor((zero_data1[,6:15]), method = "spearman")
heatmap(cor_raw1, Colv = NA, Rowv = NA, main = "Correlation of 0 inflated no covariates")

Save the Counts

write.csv(meta_counts, here("Data","GLV_SimData", "Dataset_3", "GLV_N10.csv"))
write.csv(Long_data_new, here("Data","GLV_SimData", "Dataset_3","GLV_Cov_N10.csv"))
write.csv(zero_data1, here("Data","GLV_SimData", "Dataset_3","GLV_CovZero_N10.csv"))

3. Simulate N = 20


Simulate Counts
Simulate GLV for 20 species, 50 individuals, 10 timepoints, dense n

# Set seed
set.seed(12345)

# Step 1 Run GLV for n number of subject and timepoints
###############################################################################

# Generate interactions from uniform distribution
A_uniform <- randomA(
    n_species = 20,
    diagonal = -1.0,
    connectance = 0.9)

# Create an empty list to store the count tables for each subject
count_tables <- list()


# Loop through 50 subjects and generate count tables for each
for (i in 1:50) {
  # Set the seed for each subject
  set.seed(12345 + i)  
 # Generalized Lotka-Volterra (gLV)
  tse_glv <- simulateGLV(n_species = 20,
                       A = A_uniform,
                       t_start = 0, 
                       t_store = 10,
                       stochastic = FALSE,
                       norm = FALSE,
                       error_variance = 0.01)
  
  # Get the count table
  sim_data <- tse_glv@assays@data@listData[["counts"]]
  
  # Store the count table in the list
  count_tables[[i]] <- t(sim_data)
}

# Step 2 - Merge together
###############################################################################
# Combine all count tables into one data frame
combined_count_table <- do.call(rbind, count_tables)

# Rename the rownames based on the count table number
rownames(combined_count_table) <- paste0("Sbj", rep(1:50, each = nrow(count_tables[[1]])), "_Time", 1:10)

Create Fake Metadata
1. Sex (M or F, 50/50 Ratio) 2. Age - sample from between 18 and 45 3. BMI - sample between 18 and 35

Make Metadata and merge with the count data

# Df 1 is Metadata
########################################################
meta_data <-  expand.grid(Time = 1:10,ID = 1:50)
rownames(meta_data) <- rownames(combined_count_table)
# Set seed
set.seed(12345)
meta_data$Sex <- rep(c(0, 1), each = 50)
# Set seed
set.seed(12345)
meta_data$Age <- rep(sample(18:45, 50, replace = TRUE), each = 10)
# Set seed
set.seed(12345)
meta_data$BMI <- rep(sample(18:35, 50, replace = TRUE), each = 10)

# Center the continuous variables
meta_data$Age <- meta_data$Age - mean(meta_data$Age)
meta_data$BMI <- meta_data$BMI - mean(meta_data$BMI)


# Df 2 is Metadata merged with Counts
########################################################
#Round off and increase
combined_count_table <- as.data.frame(combined_count_table + abs(min(combined_count_table)))
combined_count_table <- (combined_count_table)*10
meta_counts <- base::merge(meta_data, combined_count_table, by ="row.names", all = TRUE)
meta_counts <- column_to_rownames(meta_counts, "Row.names")

Add in biological covariates

# Set seed
set.seed(12345)
# Addin covariates
########################################################################################
# Set up new dataframe
Long_data_new <- meta_counts


# Loop running the LM to get new variables with error that has a range of values
# Taxa 11 - 15 will have Sex effect
for (i in 16:20) {
  error <- rnorm(nrow(Long_data_new), mean = 1, sd = 0.6)
  Long_data_new[, i] <- Long_data_new[, i] + 8 * Long_data_new$Sex + error
}

# round the counts to bring them back up to 0
########################################################################################

# Add the minimum value to bring everything up to at least 0
count_table1 <- Long_data_new[,6:25]


# scale to positive and make larger
count_table1 <- count_table1 + abs(min(count_table1))
count_table1 <- round(count_table1*10)

#change Long_data_new
Long_data_new[,6:25] <- count_table1

Now Add in 0s

# Set up new dataframe
predata_0 <- count_table1

# Add the 0s back in
########################################################################################


# Step 1: Calculate total counts for each column
total_counts <- colSums(predata_0)


# Step 2: Create probability gradient
gradient <- seq(0.5, 0.2, length.out = ncol(predata_0))

# Step 3: Make the probability gradient inverse to total counts (ie higher total value, lower proportion of 0s)
total_counts <- total_counts[order(total_counts)]
gradient <- gradient[order(-gradient)]

# Step 4 & 5: Generate random numbers and set counts to 0 based on probability gradient

for (i in seq_along(total_counts)) {
  prob <- gradient[i]
  # Calculate number of 0s to add based on probability
  num_zeros <- sum(runif(nrow(predata_0)) <= prob)
  # Randomly select rows to set to 0
  # Set seed
  set.seed(12345+i)
  rows_to_zero <- sample(nrow(predata_0), num_zeros)
  # Set counts to 0
  predata_0[rows_to_zero, i] <- 0
}

# merge with metadata for plotting
zero_data1 <- merge(meta_data, predata_0, by = 0)
zero_data1 <- column_to_rownames(zero_data1, "Row.names")
#round the counts
zero_data1[,6:25] <- round(zero_data1[,6:25])

Graphs to Check

# Individual Species Plots
########################################################
# Pivot to long data
count_long <- tidyr::pivot_longer(zero_data1, cols = starts_with("sp"), names_to = "Species")

# Plot the data
count_long %>%
  ggplot(aes(x = Time, y = value, colour = as.factor(ID),
             group = as.factor(ID), linetype = as.factor(ID))) +
  geom_line() + 
  geom_point() +
  geom_jitter() +
  ylab("Count") +
  labs(linetype = "ID", color = "ID") +
  facet_wrap(~ Species) +  # Create a panel for each species
  theme(legend.position = "none") +
  ggtitle("Time Series of N=20, 0s")



# Distribution of counts
########################################################
hist(as.matrix(zero_data1[,6:25]), breaks = 100, main = "Distribution of GLV Data", xlab = "Counts")


# Correlation matrix
cor_raw1 <- cor((zero_data1[,6:25]), method = "spearman")
heatmap(cor_raw1, Colv = NA, Rowv = NA, main = "Correlation of 0 inflated no covariates")

Save the Counts

write.csv(meta_counts, here("Data","GLV_SimData", "Dataset_3", "GLV_N20.csv"))
write.csv(Long_data_new, here("Data","GLV_SimData", "Dataset_3","GLV_Cov_N20.csv"))
write.csv(zero_data1, here("Data","GLV_SimData", "Dataset_3","GLV_CovZero_N20.csv"))

4. Simulate N = 50


Simulate Counts
Simulate GLV for 50 individuals, 50 species, 10 timepoints, dense n

# Set seed
set.seed(12345)

# Step 1 Run GLV for n number of subject and timepoints
###############################################################################

# Generate interactions from uniform distribution
A_uniform <- randomA(
    n_species = 50,
    diagonal = -1.0,
    connectance = 0.9)

# Create an empty list to store the count tables for each subject
count_tables <- list()


# Loop through 50 subjects and generate count tables for each
for (i in 1:50) {
  # Set the seed for each subject
  set.seed(12345 + i)  
 # Generalized Lotka-Volterra (gLV)
  tse_glv <- simulateGLV(n_species = 50,
                       A = A_uniform,
                       t_start = 0, 
                       t_store = 10,
                       stochastic = FALSE,
                       norm = FALSE,
                       error_variance = 0.01)
  
  # Get the count table
  sim_data <- tse_glv@assays@data@listData[["counts"]]
  
  # Store the count table in the list
  count_tables[[i]] <- t(sim_data)
}

# Step 2 - Merge together
###############################################################################
# Combine all count tables into one data frame
combined_count_table <- do.call(rbind, count_tables)

# Rename the rownames based on the count table number
rownames(combined_count_table) <- paste0("Sbj", rep(1:50, each = nrow(count_tables[[1]])), "_Time", 1:10)

Create Fake Metadata
1. Sex (M or F, 50/50 Ratio) 2. Age - sample from between 18 and 45 3. BMI - sample between 18 and 35

Make Metadata and merge with the count data

# Set seed
set.seed(12345)
# Df 1 is Metadata
########################################################
meta_data <-  expand.grid(Time = 1:10,ID = 1:50)
rownames(meta_data) <- rownames(combined_count_table)
# Set seed
set.seed(12345)
meta_data$Sex <- rep(c(0, 1), each = 50)
# Set seed
set.seed(12345)
meta_data$Age <- rep(sample(18:45, 50, replace = TRUE), each = 10)
# Set seed
set.seed(12345)
meta_data$BMI <- rep(sample(18:35, 50, replace = TRUE), each = 10)

# Center the continuous variables
meta_data$Age <- meta_data$Age - mean(meta_data$Age)
meta_data$BMI <- meta_data$BMI - mean(meta_data$BMI)


# Df 2 is Metadata merged with Counts
########################################################
#Round off and increase
combined_count_table <- as.data.frame(combined_count_table + abs(min(combined_count_table)))
combined_count_table <- (combined_count_table)*10
meta_counts <- base::merge(meta_data, combined_count_table, by ="row.names", all = TRUE)
meta_counts <- column_to_rownames(meta_counts, "Row.names")

Add in biological covariates

# Set seed
set.seed(12345)
# Addin covariates
########################################################################################
# Set up new dataframe
Long_data_new <- meta_counts


# Taxa 21 - 30 will have Sex effect
for (i in 26:35) {
  error <- rnorm(nrow(Long_data_new), mean = 1, sd = 0.6)
  Long_data_new[, i] <- Long_data_new[, i] + 8 * Long_data_new$Sex + error
}

# round the counts to bring them back up to 0
########################################################################################

# Add the minimum value to bring everything up to at least 0
count_table1 <- Long_data_new[,6:55]


# scale to positive and make larger
count_table1 <- count_table1 + abs(min(count_table1))
count_table1 <- round(count_table1*10)

#change Long_data_new
Long_data_new[,6:55] <- count_table1

Now Add in 0s

# Set up new dataframe
predata_0 <- count_table1

# Add the 0s back in
########################################################################################


# Step 1: Calculate total counts for each column
total_counts <- colSums(predata_0)


# Step 2: Create probability gradient
gradient <- seq(0.5, 0.2, length.out = ncol(predata_0))

# Step 3: Make the probability gradient inverse to total counts (ie higher total value, lower proportion of 0s)
total_counts <- total_counts[order(total_counts)]
gradient <- gradient[order(-gradient)]

# Step 4 & 5: Generate random numbers and set counts to 0 based on probability gradient

for (i in seq_along(total_counts)) {
  prob <- gradient[i]
  # Calculate number of 0s to add based on probability
  num_zeros <- sum(runif(nrow(predata_0)) <= prob)
  # Randomly select rows to set to 0
  # Set seed
  set.seed(12345+i)
  rows_to_zero <- sample(nrow(predata_0), num_zeros)
  # Set counts to 0
  predata_0[rows_to_zero, i] <- 0
}

# merge with metadata for plotting
zero_data1 <- merge(meta_data, predata_0, by = 0)
zero_data1 <- column_to_rownames(zero_data1, "Row.names")
#round the counts
zero_data1[,6:55] <- round(zero_data1[,6:55])

Graphs to Check

# Individual Species Plots
########################################################
# Pivot to long data
count_long <- tidyr::pivot_longer(zero_data1, cols = starts_with("sp"), names_to = "Species")

# Plot the data
count_long %>%
  ggplot(aes(x = Time, y = value, colour = as.factor(ID),
             group = as.factor(ID), linetype = as.factor(ID))) +
  geom_line() + 
  geom_point() +
  geom_jitter() +
  ylab("Count") +
  labs(linetype = "ID", color = "ID") +
  facet_wrap(~ Species) +  # Create a panel for each species
  theme(legend.position = "none") +
  ggtitle("Time Series of N=50, 0s")



# Distribution of counts
########################################################
hist(as.matrix(zero_data1[,6:55]), breaks = 100, main = "Distribution of GLV Data", xlab = "Counts")


# Correlation matrix
cor_raw1 <- cor((zero_data1[,6:55]), method = "spearman")
heatmap(cor_raw1, Colv = NA, Rowv = NA, main = "Correlation of 0 inflated no covariates")

Save the Counts

write.csv(meta_counts, here("Data","GLV_SimData", "Dataset_3","GLV_N50.csv"))
write.csv(Long_data_new, here("Data","GLV_SimData", "Dataset_3","GLV_Cov_N50.csv"))
write.csv(zero_data1, here("Data","GLV_SimData", "Dataset_3","GLV_CovZero_N50.csv"))

5. Simulate N = 75


Simulate Counts
Simulate GLV for 75 species, 50 individuals, 10 timepoints, dense n

# Set seed
set.seed(12345)

# Step 1 Run GLV for n number of subject and timepoints
###############################################################################

# Generate interactions from uniform distribution
A_uniform <- randomA(
    n_species = 75,
    diagonal = -1.0,
    connectance = 0.9)

# Create an empty list to store the count tables for each subject
count_tables <- list()


# Loop through 50 subjects and generate count tables for each
for (i in 1:50) {
  # Set the seed for each subject
  set.seed(12345 + i)  
 # Generalized Lotka-Volterra (gLV)
  tse_glv <- simulateGLV(n_species = 75,
                       A = A_uniform,
                       t_start = 0, 
                       t_store = 10,
                       stochastic = FALSE,
                       norm = FALSE,
                       error_variance = 0.01)
  
  # Get the count table
  sim_data <- tse_glv@assays@data@listData[["counts"]]
  
  # Store the count table in the list
  count_tables[[i]] <- t(sim_data)
}

# Step 2 - Merge together
###############################################################################
# Combine all count tables into one data frame
combined_count_table <- do.call(rbind, count_tables)

# Rename the rownames based on the count table number
rownames(combined_count_table) <- paste0("Sbj", rep(1:50, each = nrow(count_tables[[1]])), "_Time", 1:10)

Create Fake Metadata
1. Sex (M or F, 50/50 Ratio) 2. Age - sample from between 18 and 45 3. BMI - sample between 18 and 35

Make Metadata and merge with the count data

# Set seed
set.seed(12345)
# Df 1 is Metadata
########################################################
meta_data <-  expand.grid(Time = 1:10,ID = 1:50)
rownames(meta_data) <- rownames(combined_count_table)
# Set seed
set.seed(12345)
meta_data$Sex <- rep(c(0, 1), each = 50)
# Set seed
set.seed(12345)
meta_data$Age <- rep(sample(18:45, 50, replace = TRUE), each = 10)
# Set seed
set.seed(12345)
meta_data$BMI <- rep(sample(18:35, 50, replace = TRUE), each = 10)

# Center the continuous variables
meta_data$Age <- meta_data$Age - mean(meta_data$Age)
meta_data$BMI <- meta_data$BMI - mean(meta_data$BMI)


# Df 2 is Metadata merged with Counts
########################################################
#Round off and increase
combined_count_table <- as.data.frame(combined_count_table + abs(min(combined_count_table)))
combined_count_table <- (combined_count_table)*10
meta_counts <- base::merge(meta_data, combined_count_table, by ="row.names", all = TRUE)
meta_counts <- column_to_rownames(meta_counts, "Row.names")

Add in biological covariates

# Set seed
set.seed(12345)
# Addin covariates
########################################################################################
# Set up new dataframe
Long_data_new <- meta_counts


# Loop running the LM to get new variables with error that has a range of values

# Taxa 41 - 60 will have Sex effect
for (i in 46:65) {
  error <- rnorm(nrow(Long_data_new), mean = 1, sd = 0.6)
  Long_data_new[, i] <- Long_data_new[, i] + 8 * Long_data_new$Sex + error
}

# round the counts to bring them back up to 0
########################################################################################

# Add the minimum value to bring everything up to at least 0
count_table1 <- Long_data_new[,6:80]


# scale to positive and make larger
count_table1 <- count_table1 + abs(min(count_table1))
count_table1 <- round(count_table1*10)

#change Long_data_new
Long_data_new[,6:80] <- count_table1

Now Add in 0s

# Set up new dataframe
predata_0 <- count_table1

# Add the 0s back in
########################################################################################


# Step 1: Calculate total counts for each column
total_counts <- colSums(predata_0)


# Step 2: Create probability gradient
gradient <- seq(0.5, 0.2, length.out = ncol(predata_0))

# Step 3: Make the probability gradient inverse to total counts (ie higher total value, lower proportion of 0s)
total_counts <- total_counts[order(total_counts)]
gradient <- gradient[order(-gradient)]

# Step 4 & 5: Generate random numbers and set counts to 0 based on probability gradient

for (i in seq_along(total_counts)) {
  prob <- gradient[i]
  # Calculate number of 0s to add based on probability
  num_zeros <- sum(runif(nrow(predata_0)) <= prob)
  # Randomly select rows to set to 0
  # Set seed
  set.seed(12345+i)
  rows_to_zero <- sample(nrow(predata_0), num_zeros)
  # Set counts to 0
  predata_0[rows_to_zero, i] <- 0
}

# merge with metadata for plotting
zero_data1 <- merge(meta_data, predata_0, by = 0)
zero_data1 <- column_to_rownames(zero_data1, "Row.names")
#round the counts
zero_data1[,6:80] <- round(zero_data1[,6:80])

Graphs to Check

# Individual Species Plots
########################################################
# Pivot to long data
count_long <- tidyr::pivot_longer(zero_data1, cols = starts_with("sp"), names_to = "Species")

# Plot the data
count_long %>%
  ggplot(aes(x = Time, y = value, colour = as.factor(ID),
             group = as.factor(ID), linetype = as.factor(ID))) +
  geom_line() + 
  geom_point() +
  geom_jitter() +
  ylab("Count") +
  labs(linetype = "ID", color = "ID") +
  facet_wrap(~ Species) +  # Create a panel for each species
  theme(legend.position = "none") +
  ggtitle("Time Series of N=50, 0s")



# Distribution of counts
########################################################
hist(as.matrix(zero_data1[,6:80]), breaks = 100, main = "Distribution of GLV Data", xlab = "Counts")


# Correlation matrix
cor_raw1 <- cor((zero_data1[,6:80]), method = "spearman")
heatmap(cor_raw1, Colv = NA, Rowv = NA, main = "Correlation of 0 inflated no covariates")

Save the Counts

write.csv(meta_counts, here("Data","GLV_SimData", "Dataset_3","GLV_N75.csv"))
write.csv(Long_data_new, here("Data","GLV_SimData", "Dataset_3","GLV_Cov_N75.csv"))
write.csv(zero_data1, here("Data","GLV_SimData", "Dataset_3","GLV_CovZero_N75.csv"))

6. Simulate N = 100


Simulate Counts
Simulate GLV for 100 species, 50 individuals, 10 timepoints, dense n

# Set seed
set.seed(12345)

# Step 1 Run GLV for n number of subject and timepoints
###############################################################################

# Generate interactions from uniform distribution
A_uniform <- randomA(
    n_species = 100,
    diagonal = -1.0,
    connectance = 0.9)

# Create an empty list to store the count tables for each subject
count_tables <- list()


# Loop through 50 subjects and generate count tables for each
for (i in 1:50) {
  # Set the seed for each subject
  set.seed(12345 + i)  
 # Generalized Lotka-Volterra (gLV)
  tse_glv <- simulateGLV(n_species = 100,
                       A = A_uniform,
                       t_start = 0, 
                       t_store = 10,
                       stochastic = FALSE,
                       norm = FALSE,
                       error_variance = 0.01)
  
  # Get the count table
  sim_data <- tse_glv@assays@data@listData[["counts"]]
  
  # Store the count table in the list
  count_tables[[i]] <- t(sim_data)
}

# Step 2 - Merge together
###############################################################################
# Combine all count tables into one data frame
combined_count_table <- do.call(rbind, count_tables)

# Rename the rownames based on the count table number
rownames(combined_count_table) <- paste0("Sbj", rep(1:50, each = nrow(count_tables[[1]])), "_Time", 1:10)

Create Fake Metadata
1. Sex (M or F, 50/50 Ratio) 2. Age - sample from between 18 and 45 3. BMI - sample between 18 and 35

Make Metadata and merge with the count data

# Set seed
set.seed(12345)
# Df 1 is Metadata
########################################################
meta_data <-  expand.grid(Time = 1:10,ID = 1:50)
rownames(meta_data) <- rownames(combined_count_table)
# Set seed
set.seed(12345)
meta_data$Sex <- rep(c(0, 1), each = 50)
# Set seed
set.seed(12345)
meta_data$Age <- rep(sample(18:45, 50, replace = TRUE), each = 10)
# Set seed
set.seed(12345)
meta_data$BMI <- rep(sample(18:35, 50, replace = TRUE), each = 10)

# Center the continuous variables
meta_data$Age <- meta_data$Age - mean(meta_data$Age)
meta_data$BMI <- meta_data$BMI - mean(meta_data$BMI)


# Df 2 is Metadata merged with Counts
########################################################
#Round off and increase
combined_count_table <- as.data.frame(combined_count_table + abs(min(combined_count_table)))
combined_count_table <- (combined_count_table)*10
meta_counts <- base::merge(meta_data, combined_count_table, by ="row.names", all = TRUE)
meta_counts <- column_to_rownames(meta_counts, "Row.names")

Add in biological covariates

# Set seed
set.seed(12345)
# Addin covariates
########################################################################################
# Set up new dataframe
Long_data_new <- meta_counts


# Loop running the LM to get new variables with error that has a range of values
# Taxa 51 - 75 will have Sex effect
for (i in 56:80) {
  error <- rnorm(nrow(Long_data_new), mean = 1, sd = 0.6)
  Long_data_new[, i] <- Long_data_new[, i] + 8 * Long_data_new$Sex + error
}

# round the counts to bring them back up to 0
########################################################################################

# Add the minimum value to bring everything up to at least 0
count_table1 <- Long_data_new[,6:105]


# scale to positive and make larger
count_table1 <- count_table1 + abs(min(count_table1))
count_table1 <- round(count_table1*10)

#change Long_data_new
Long_data_new[,6:105] <- count_table1

Now Add in 0s

# Set up new dataframe
predata_0 <- count_table1

# Add the 0s back in
########################################################################################


# Step 1: Calculate total counts for each column
total_counts <- colSums(predata_0)


# Step 2: Create probability gradient
gradient <- seq(0.5, 0.2, length.out = ncol(predata_0))

# Step 3: Make the probability gradient inverse to total counts (ie higher total value, lower proportion of 0s)
total_counts <- total_counts[order(total_counts)]
gradient <- gradient[order(-gradient)]

# Step 4 & 5: Generate random numbers and set counts to 0 based on probability gradient

for (i in seq_along(total_counts)) {
  prob <- gradient[i]
  # Calculate number of 0s to add based on probability
  num_zeros <- sum(runif(nrow(predata_0)) <= prob)
  # Randomly select rows to set to 0
  # Set seed
  set.seed(12345+i)
  rows_to_zero <- sample(nrow(predata_0), num_zeros)
  # Set counts to 0
  predata_0[rows_to_zero, i] <- 0
}

# merge with metadata for plotting
zero_data1 <- merge(meta_data, predata_0, by = 0)
zero_data1 <- column_to_rownames(zero_data1, "Row.names")
#round the counts
zero_data1[,6:105] <- round(zero_data1[,6:105])

Graphs to Check

# Individual Species Plots
########################################################
# Pivot to long data
count_long <- tidyr::pivot_longer(zero_data1, cols = starts_with("sp"), names_to = "Species")

# Plot the data
count_long %>%
  ggplot(aes(x = Time, y = value, colour = as.factor(ID),
             group = as.factor(ID), linetype = as.factor(ID))) +
  geom_line() + 
  geom_point() +
  geom_jitter() +
  ylab("Count") +
  labs(linetype = "ID", color = "ID") +
  facet_wrap(~ Species) +  # Create a panel for each species
  theme(legend.position = "none") +
  ggtitle("Time Series of N=100, 0s")



# Distribution of counts
########################################################
hist(as.matrix(zero_data1[,6:105]), breaks = 100, main = "Distribution of GLV Data", xlab = "Counts")


# Correlation matrix
cor_raw1 <- cor((zero_data1[,6:105]), method = "spearman")
heatmap(cor_raw1, Colv = NA, Rowv = NA, main = "Correlation of 0 inflated no covariates")

Save the Counts

write.csv(meta_counts, here("Data","GLV_SimData", "Dataset_3","GLV_N100.csv"))
write.csv(Long_data_new, here("Data","GLV_SimData", "Dataset_3","GLV_Cov_N100.csv"))
write.csv(zero_data1, here("Data","GLV_SimData", "Dataset_3","GLV_CovZero_N100.csv"))
LS0tCnRpdGxlOiAiRGF0YSBTaW11bGF0aW9uIGZvciBUYXhhIFNpemUiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCkluIHRoaXMgc2NyaXB0LCBzaW11bGF0ZSA1IGRpZmZlcmVudCBkYXRhc2V0cyBiYXNlZCBvbiBOIHZhbHVlLiBFYWNoIHdpbGwgYmUgYSBHTFYgbW9kZWwgb2YgNTAgc3ViamVjdHMgb3ZlciAxMCB0aW1lIHBvaW50cyB3aXRoIHRoZSBzYW1lIHN0YXJ0aW5nIGNvcnJlbGF0aW9uIG1hdHJpeC4gTiB2YWx1ZXMgYXJlIDEwLCAyMCwgNTAsIDc1IGFuZCAxMDAgdGF4YSAKCiMgMS4gTG9hZCBMaWJyYXJ5CioqKiAKCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoaWdyYXBoKQpsaWJyYXJ5KE5CWklNTSkKbGlicmFyeShTcGllY0Vhc2kpCmxpYnJhcnkoTElNT04pCmxpYnJhcnkoaGVyZSkKbGlicmFyeShsbWU0KQpsaWJyYXJ5KE1hdHJpeCkKbGlicmFyeSh0c2NvdW50KQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShNQVNTKQpsaWJyYXJ5KG1hdHJpeGNhbGMpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KGRldnRvb2xzKQpsaWJyYXJ5KG1pYVNpbSkKbGlicmFyeShyZXNoYXBlMikKYGBgCgoKCiMgMi4gU2ltdWxhdGUgTiA9IDEwCioqKiAKCl9fU2ltdWxhdGUgQ291bnRzX18gIApTaW11bGF0ZSBHTFYgZm9yIDEwIHNwZWNpZXMsIDUwIGluZGl2aWR1YWxzLCAxMCB0aW1lIHBvaW50cywgZGVuc2UgbgpgYGB7cn0KIyBTZXQgc2VlZApzZXQuc2VlZCgxMjM0NSkKCiMgU3RlcCAxIFJ1biBHTFYgZm9yIG4gbnVtYmVyIG9mIHN1YmplY3QgYW5kIHRpbWVwb2ludHMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyBHZW5lcmF0ZSBpbnRlcmFjdGlvbnMgZnJvbSB1bmlmb3JtIGRpc3RyaWJ1dGlvbgpBX3VuaWZvcm0gPC0gcmFuZG9tQSgKICAgIG5fc3BlY2llcyA9IDEwLAogICAgZGlhZ29uYWwgPSAtMS4wLAogICAgY29ubmVjdGFuY2UgPSAwLjkpCgojIENyZWF0ZSBhbiBlbXB0eSBsaXN0IHRvIHN0b3JlIHRoZSBjb3VudCB0YWJsZXMgZm9yIGVhY2ggc3ViamVjdApjb3VudF90YWJsZXMgPC0gbGlzdCgpCgoKIyBMb29wIHRocm91Z2ggc3ViamVjdHMgYW5kIGdlbmVyYXRlIGNvdW50IHRhYmxlcyBmb3IgZWFjaApmb3IgKGkgaW4gMTo1MCkgewogICMgU2V0IHRoZSBzZWVkIGZvciBlYWNoIHN1YmplY3QKICBzZXQuc2VlZCgxMjM0NSArIGkpICAKICMgR2VuZXJhbGl6ZWQgTG90a2EtVm9sdGVycmEgKGdMVikKICB0c2VfZ2x2IDwtIHNpbXVsYXRlR0xWKG5fc3BlY2llcyA9IDEwLAogICAgICAgICAgICAgICAgICAgICAgIEEgPSBBX3VuaWZvcm0sCiAgICAgICAgICAgICAgICAgICAgICAgdF9zdGFydCA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgIHRfc3RvcmUgPSAxMCwKICAgICAgICAgICAgICAgICAgICAgICBzdG9jaGFzdGljID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgbm9ybSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgIGVycm9yX3ZhcmlhbmNlID0gMC4wMSkKICAKICAjIEdldCB0aGUgY291bnQgdGFibGUKICBzaW1fZGF0YSA8LSB0c2VfZ2x2QGFzc2F5c0BkYXRhQGxpc3REYXRhW1siY291bnRzIl1dCiAgCiAgIyBTdG9yZSB0aGUgY291bnQgdGFibGUgaW4gdGhlIGxpc3QKICBjb3VudF90YWJsZXNbW2ldXSA8LSB0KHNpbV9kYXRhKQp9CgojIFN0ZXAgMiAtIE1lcmdlIHRvZ2V0aGVyCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBDb21iaW5lIGFsbCBjb3VudCB0YWJsZXMgaW50byBvbmUgZGF0YSBmcmFtZQpjb21iaW5lZF9jb3VudF90YWJsZSA8LSBkby5jYWxsKHJiaW5kLCBjb3VudF90YWJsZXMpCgojIFJlbmFtZSB0aGUgcm93bmFtZXMgYmFzZWQgb24gdGhlIGNvdW50IHRhYmxlIG51bWJlcgpyb3duYW1lcyhjb21iaW5lZF9jb3VudF90YWJsZSkgPC0gcGFzdGUwKCJTYmoiLCByZXAoMTo1MCwgZWFjaCA9IG5yb3coY291bnRfdGFibGVzW1sxXV0pKSwgIl9UaW1lIiwgMToxMCkKCmBgYAoKCl9fQ3JlYXRlIEZha2UgTWV0YWRhdGFfXyAgCjEuIFNleCAoTSBvciBGLCA1MC81MCBSYXRpbykKMi4gQWdlIC0gc2FtcGxlIGZyb20gYmV0d2VlbiAxOCBhbmQgNDUKMy4gQk1JIC0gc2FtcGxlIGJldHdlZW4gMTggYW5kIDM1CgpNYWtlIE1ldGFkYXRhIGFuZCBtZXJnZSB3aXRoIHRoZSBjb3VudCBkYXRhCmBgYHtyfQojIERmIDEgaXMgTWV0YWRhdGEKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKbWV0YV9kYXRhIDwtICBleHBhbmQuZ3JpZChUaW1lID0gMToxMCxJRCA9IDE6NTApCnJvd25hbWVzKG1ldGFfZGF0YSkgPC0gcm93bmFtZXMoY29tYmluZWRfY291bnRfdGFibGUpCiMgU2V0IHNlZWQKc2V0LnNlZWQoMTIzNDUpCm1ldGFfZGF0YSRTZXggPC0gcmVwKGMoMCwgMSksIGVhY2ggPSA1MCkKIyBTZXQgc2VlZApzZXQuc2VlZCgxMjM0NSkKbWV0YV9kYXRhJEFnZSA8LSByZXAoc2FtcGxlKDE4OjQ1LCA1MCwgcmVwbGFjZSA9IFRSVUUpLCBlYWNoID0gMTApCiMgU2V0IHNlZWQKc2V0LnNlZWQoMTIzNDUpCm1ldGFfZGF0YSRCTUkgPC0gcmVwKHNhbXBsZSgxODozNSwgNTAsIHJlcGxhY2UgPSBUUlVFKSwgZWFjaCA9IDEwKQoKIyBDZW50ZXIgdGhlIGNvbnRpbnVvdXMgdmFyaWFibGVzCm1ldGFfZGF0YSRBZ2UgPC0gbWV0YV9kYXRhJEFnZSAtIG1lYW4obWV0YV9kYXRhJEFnZSkKbWV0YV9kYXRhJEJNSSA8LSBtZXRhX2RhdGEkQk1JIC0gbWVhbihtZXRhX2RhdGEkQk1JKQoKCiMgRGYgMiBpcyBNZXRhZGF0YSBtZXJnZWQgd2l0aCBDb3VudHMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKI1JvdW5kIG9mZiBhbmQgaW5jcmVhc2UKY29tYmluZWRfY291bnRfdGFibGUgPC0gYXMuZGF0YS5mcmFtZShjb21iaW5lZF9jb3VudF90YWJsZSArIGFicyhtaW4oY29tYmluZWRfY291bnRfdGFibGUpKSkKY29tYmluZWRfY291bnRfdGFibGUgPC0gKGNvbWJpbmVkX2NvdW50X3RhYmxlKSoxMAptZXRhX2NvdW50cyA8LSBiYXNlOjptZXJnZShtZXRhX2RhdGEsIGNvbWJpbmVkX2NvdW50X3RhYmxlLCBieSA9InJvdy5uYW1lcyIsIGFsbCA9IFRSVUUpCm1ldGFfY291bnRzIDwtIGNvbHVtbl90b19yb3duYW1lcyhtZXRhX2NvdW50cywgIlJvdy5uYW1lcyIpCgoKYGBgCgoKQWRkIGluIGJpb2xvZ2ljYWwgY292YXJpYXRlcwpgYGB7cn0KIyBTZXQgc2VlZApzZXQuc2VlZCgxMjM0NSkKIyBBZGRpbiBjb3ZhcmlhdGVzCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBTZXQgdXAgbmV3IGRhdGFmcmFtZQpMb25nX2RhdGFfbmV3IDwtIG1ldGFfY291bnRzCgoKIyBMb29wIHJ1bm5pbmcgdGhlIExNIHRvIGdldCBuZXcgdmFyaWFibGVzIHdpdGggZXJyb3IgdGhhdCBoYXMgYSByYW5nZSBvZiB2YWx1ZXMKIyBUYXhhIDcgLSA4IHdpbGwgaGF2ZSBTZXggZWZmZWN0CmZvciAoaSBpbiAxMjoxMykgewogIGVycm9yIDwtIHJub3JtKG5yb3coTG9uZ19kYXRhX25ldyksIG1lYW4gPSAxLCBzZCA9IDAuNikKICBMb25nX2RhdGFfbmV3WywgaV0gPC0gTG9uZ19kYXRhX25ld1ssIGldICsgOCAqIExvbmdfZGF0YV9uZXckU2V4ICsgZXJyb3IKfQoKIyByb3VuZCB0aGUgY291bnRzIHRvIGJyaW5nIHRoZW0gYmFjayB1cCB0byAwCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiMgQWRkIHRoZSBtaW5pbXVtIHZhbHVlIHRvIGJyaW5nIGV2ZXJ5dGhpbmcgdXAgdG8gYXQgbGVhc3QgMApjb3VudF90YWJsZTEgPC0gTG9uZ19kYXRhX25ld1ssNjoxNV0KCgojIHNjYWxlIHRvIHBvc2l0aXZlIGFuZCBtYWtlIGxhcmdlcgpjb3VudF90YWJsZTEgPC0gY291bnRfdGFibGUxICsgYWJzKG1pbihjb3VudF90YWJsZTEpKQpjb3VudF90YWJsZTEgPC0gcm91bmQoY291bnRfdGFibGUxKjEwKQoKI2NoYW5nZSBMb25nX2RhdGFfbmV3CkxvbmdfZGF0YV9uZXdbLDY6MTVdIDwtIGNvdW50X3RhYmxlMQpgYGAKCgoKTm93IEFkZCBpbiAwcwpgYGB7cn0KIyBTZXQgdXAgbmV3IGRhdGFmcmFtZQpwcmVkYXRhXzAgPC0gY291bnRfdGFibGUxCgojIEFkZCB0aGUgMHMgYmFjayBpbgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgoKIyBTdGVwIDE6IENhbGN1bGF0ZSB0b3RhbCBjb3VudHMgZm9yIGVhY2ggY29sdW1uCnRvdGFsX2NvdW50cyA8LSBjb2xTdW1zKHByZWRhdGFfMCkKCgojIFN0ZXAgMjogQ3JlYXRlIHByb2JhYmlsaXR5IGdyYWRpZW50CmdyYWRpZW50IDwtIHNlcSgwLjUsIDAuMiwgbGVuZ3RoLm91dCA9IG5jb2wocHJlZGF0YV8wKSkKCiMgU3RlcCAzOiBNYWtlIHRoZSBwcm9iYWJpbGl0eSBncmFkaWVudCBpbnZlcnNlIHRvIHRvdGFsIGNvdW50cyAoaWUgaGlnaGVyIHRvdGFsIHZhbHVlLCBsb3dlciBwcm9wb3J0aW9uIG9mIDBzKQp0b3RhbF9jb3VudHMgPC0gdG90YWxfY291bnRzW29yZGVyKHRvdGFsX2NvdW50cyldCmdyYWRpZW50IDwtIGdyYWRpZW50W29yZGVyKC1ncmFkaWVudCldCgojIFN0ZXAgNCAmIDU6IEdlbmVyYXRlIHJhbmRvbSBudW1iZXJzIGFuZCBzZXQgY291bnRzIHRvIDAgYmFzZWQgb24gcHJvYmFiaWxpdHkgZ3JhZGllbnQKCmZvciAoaSBpbiBzZXFfYWxvbmcodG90YWxfY291bnRzKSkgewogIHByb2IgPC0gZ3JhZGllbnRbaV0KICAjIENhbGN1bGF0ZSBudW1iZXIgb2YgMHMgdG8gYWRkIGJhc2VkIG9uIHByb2JhYmlsaXR5CiAgbnVtX3plcm9zIDwtIHN1bShydW5pZihucm93KHByZWRhdGFfMCkpIDw9IHByb2IpCiAgIyBSYW5kb21seSBzZWxlY3Qgcm93cyB0byBzZXQgdG8gMAogICMgU2V0IHNlZWQKICBzZXQuc2VlZCgxMjM0NStpKQogIHJvd3NfdG9femVybyA8LSBzYW1wbGUobnJvdyhwcmVkYXRhXzApLCBudW1femVyb3MpCiAgIyBTZXQgY291bnRzIHRvIDAKICBwcmVkYXRhXzBbcm93c190b196ZXJvLCBpXSA8LSAwCn0KCiMgbWVyZ2Ugd2l0aCBtZXRhZGF0YSBmb3IgcGxvdHRpbmcKemVyb19kYXRhMSA8LSBtZXJnZShtZXRhX2RhdGEsIHByZWRhdGFfMCwgYnkgPSAwKQp6ZXJvX2RhdGExIDwtIGNvbHVtbl90b19yb3duYW1lcyh6ZXJvX2RhdGExLCAiUm93Lm5hbWVzIikKI3JvdW5kIHRoZSBjb3VudHMKemVyb19kYXRhMVssNjoxNV0gPC0gcm91bmQoemVyb19kYXRhMVssNjoxNV0pCmBgYAoKR3JhcGhzIHRvIENoZWNrCmBgYHtyfQojIEluZGl2aWR1YWwgU3BlY2llcyBQbG90cwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIFBpdm90IHRvIGxvbmcgZGF0YQpjb3VudF9sb25nIDwtIHRpZHlyOjpwaXZvdF9sb25nZXIoemVyb19kYXRhMSwgY29scyA9IHN0YXJ0c193aXRoKCJzcCIpLCBuYW1lc190byA9ICJTcGVjaWVzIikKCiMgUGxvdCB0aGUgZGF0YQpjb3VudF9sb25nICU+JQogIGdncGxvdChhZXMoeCA9IFRpbWUsIHkgPSB2YWx1ZSwgY29sb3VyID0gYXMuZmFjdG9yKElEKSwKICAgICAgICAgICAgIGdyb3VwID0gYXMuZmFjdG9yKElEKSwgbGluZXR5cGUgPSBhcy5mYWN0b3IoSUQpKSkgKwogIGdlb21fbGluZSgpICsgCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2ppdHRlcigpICsKICB5bGFiKCJDb3VudCIpICsKICBsYWJzKGxpbmV0eXBlID0gIklEIiwgY29sb3IgPSAiSUQiKSArCiAgZmFjZXRfd3JhcCh+IFNwZWNpZXMpICsgICMgQ3JlYXRlIGEgcGFuZWwgZm9yIGVhY2ggc3BlY2llcwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGdndGl0bGUoIlRpbWUgU2VyaWVzIG9mIE49MTAsIDBzIikKCgojIERpc3RyaWJ1dGlvbiBvZiBjb3VudHMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKaGlzdChhcy5tYXRyaXgoemVyb19kYXRhMVssNjoxNV0pLCBicmVha3MgPSAxMDAsIG1haW4gPSAiRGlzdHJpYnV0aW9uIG9mIEdMViBEYXRhIiwgeGxhYiA9ICJDb3VudHMiKQoKIyBDb3JyZWxhdGlvbiBtYXRyaXgKY29yX3JhdzEgPC0gY29yKCh6ZXJvX2RhdGExWyw2OjE1XSksIG1ldGhvZCA9ICJzcGVhcm1hbiIpCmhlYXRtYXAoY29yX3JhdzEsIENvbHYgPSBOQSwgUm93diA9IE5BLCBtYWluID0gIkNvcnJlbGF0aW9uIG9mIDAgaW5mbGF0ZWQgbm8gY292YXJpYXRlcyIpCmBgYAoKClNhdmUgdGhlIENvdW50cwpgYGB7cn0Kd3JpdGUuY3N2KG1ldGFfY291bnRzLCBoZXJlKCJEYXRhIiwiR0xWX1NpbURhdGEiLCAiRGF0YXNldF8zIiwgIkdMVl9OMTAuY3N2IikpCndyaXRlLmNzdihMb25nX2RhdGFfbmV3LCBoZXJlKCJEYXRhIiwiR0xWX1NpbURhdGEiLCAiRGF0YXNldF8zIiwiR0xWX0Nvdl9OMTAuY3N2IikpCndyaXRlLmNzdih6ZXJvX2RhdGExLCBoZXJlKCJEYXRhIiwiR0xWX1NpbURhdGEiLCAiRGF0YXNldF8zIiwiR0xWX0Nvdlplcm9fTjEwLmNzdiIpKQpgYGAKCgojIDMuIFNpbXVsYXRlIE4gPSAyMAoqKiogCgpfX1NpbXVsYXRlIENvdW50c19fICAKU2ltdWxhdGUgR0xWIGZvciAyMCBzcGVjaWVzLCA1MCBpbmRpdmlkdWFscywgMTAgdGltZXBvaW50cywgZGVuc2UgbgpgYGB7cn0KIyBTZXQgc2VlZApzZXQuc2VlZCgxMjM0NSkKCiMgU3RlcCAxIFJ1biBHTFYgZm9yIG4gbnVtYmVyIG9mIHN1YmplY3QgYW5kIHRpbWVwb2ludHMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyBHZW5lcmF0ZSBpbnRlcmFjdGlvbnMgZnJvbSB1bmlmb3JtIGRpc3RyaWJ1dGlvbgpBX3VuaWZvcm0gPC0gcmFuZG9tQSgKICAgIG5fc3BlY2llcyA9IDIwLAogICAgZGlhZ29uYWwgPSAtMS4wLAogICAgY29ubmVjdGFuY2UgPSAwLjkpCgojIENyZWF0ZSBhbiBlbXB0eSBsaXN0IHRvIHN0b3JlIHRoZSBjb3VudCB0YWJsZXMgZm9yIGVhY2ggc3ViamVjdApjb3VudF90YWJsZXMgPC0gbGlzdCgpCgoKIyBMb29wIHRocm91Z2ggNTAgc3ViamVjdHMgYW5kIGdlbmVyYXRlIGNvdW50IHRhYmxlcyBmb3IgZWFjaApmb3IgKGkgaW4gMTo1MCkgewogICMgU2V0IHRoZSBzZWVkIGZvciBlYWNoIHN1YmplY3QKICBzZXQuc2VlZCgxMjM0NSArIGkpICAKICMgR2VuZXJhbGl6ZWQgTG90a2EtVm9sdGVycmEgKGdMVikKICB0c2VfZ2x2IDwtIHNpbXVsYXRlR0xWKG5fc3BlY2llcyA9IDIwLAogICAgICAgICAgICAgICAgICAgICAgIEEgPSBBX3VuaWZvcm0sCiAgICAgICAgICAgICAgICAgICAgICAgdF9zdGFydCA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgIHRfc3RvcmUgPSAxMCwKICAgICAgICAgICAgICAgICAgICAgICBzdG9jaGFzdGljID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgbm9ybSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgIGVycm9yX3ZhcmlhbmNlID0gMC4wMSkKICAKICAjIEdldCB0aGUgY291bnQgdGFibGUKICBzaW1fZGF0YSA8LSB0c2VfZ2x2QGFzc2F5c0BkYXRhQGxpc3REYXRhW1siY291bnRzIl1dCiAgCiAgIyBTdG9yZSB0aGUgY291bnQgdGFibGUgaW4gdGhlIGxpc3QKICBjb3VudF90YWJsZXNbW2ldXSA8LSB0KHNpbV9kYXRhKQp9CgojIFN0ZXAgMiAtIE1lcmdlIHRvZ2V0aGVyCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBDb21iaW5lIGFsbCBjb3VudCB0YWJsZXMgaW50byBvbmUgZGF0YSBmcmFtZQpjb21iaW5lZF9jb3VudF90YWJsZSA8LSBkby5jYWxsKHJiaW5kLCBjb3VudF90YWJsZXMpCgojIFJlbmFtZSB0aGUgcm93bmFtZXMgYmFzZWQgb24gdGhlIGNvdW50IHRhYmxlIG51bWJlcgpyb3duYW1lcyhjb21iaW5lZF9jb3VudF90YWJsZSkgPC0gcGFzdGUwKCJTYmoiLCByZXAoMTo1MCwgZWFjaCA9IG5yb3coY291bnRfdGFibGVzW1sxXV0pKSwgIl9UaW1lIiwgMToxMCkKCmBgYAoKCl9fQ3JlYXRlIEZha2UgTWV0YWRhdGFfXyAgCjEuIFNleCAoTSBvciBGLCA1MC81MCBSYXRpbykKMi4gQWdlIC0gc2FtcGxlIGZyb20gYmV0d2VlbiAxOCBhbmQgNDUKMy4gQk1JIC0gc2FtcGxlIGJldHdlZW4gMTggYW5kIDM1CgpNYWtlIE1ldGFkYXRhIGFuZCBtZXJnZSB3aXRoIHRoZSBjb3VudCBkYXRhCmBgYHtyfQojIERmIDEgaXMgTWV0YWRhdGEKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKbWV0YV9kYXRhIDwtICBleHBhbmQuZ3JpZChUaW1lID0gMToxMCxJRCA9IDE6NTApCnJvd25hbWVzKG1ldGFfZGF0YSkgPC0gcm93bmFtZXMoY29tYmluZWRfY291bnRfdGFibGUpCiMgU2V0IHNlZWQKc2V0LnNlZWQoMTIzNDUpCm1ldGFfZGF0YSRTZXggPC0gcmVwKGMoMCwgMSksIGVhY2ggPSA1MCkKIyBTZXQgc2VlZApzZXQuc2VlZCgxMjM0NSkKbWV0YV9kYXRhJEFnZSA8LSByZXAoc2FtcGxlKDE4OjQ1LCA1MCwgcmVwbGFjZSA9IFRSVUUpLCBlYWNoID0gMTApCiMgU2V0IHNlZWQKc2V0LnNlZWQoMTIzNDUpCm1ldGFfZGF0YSRCTUkgPC0gcmVwKHNhbXBsZSgxODozNSwgNTAsIHJlcGxhY2UgPSBUUlVFKSwgZWFjaCA9IDEwKQoKIyBDZW50ZXIgdGhlIGNvbnRpbnVvdXMgdmFyaWFibGVzCm1ldGFfZGF0YSRBZ2UgPC0gbWV0YV9kYXRhJEFnZSAtIG1lYW4obWV0YV9kYXRhJEFnZSkKbWV0YV9kYXRhJEJNSSA8LSBtZXRhX2RhdGEkQk1JIC0gbWVhbihtZXRhX2RhdGEkQk1JKQoKCiMgRGYgMiBpcyBNZXRhZGF0YSBtZXJnZWQgd2l0aCBDb3VudHMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKI1JvdW5kIG9mZiBhbmQgaW5jcmVhc2UKY29tYmluZWRfY291bnRfdGFibGUgPC0gYXMuZGF0YS5mcmFtZShjb21iaW5lZF9jb3VudF90YWJsZSArIGFicyhtaW4oY29tYmluZWRfY291bnRfdGFibGUpKSkKY29tYmluZWRfY291bnRfdGFibGUgPC0gKGNvbWJpbmVkX2NvdW50X3RhYmxlKSoxMAptZXRhX2NvdW50cyA8LSBiYXNlOjptZXJnZShtZXRhX2RhdGEsIGNvbWJpbmVkX2NvdW50X3RhYmxlLCBieSA9InJvdy5uYW1lcyIsIGFsbCA9IFRSVUUpCm1ldGFfY291bnRzIDwtIGNvbHVtbl90b19yb3duYW1lcyhtZXRhX2NvdW50cywgIlJvdy5uYW1lcyIpCgoKYGBgCgoKQWRkIGluIGJpb2xvZ2ljYWwgY292YXJpYXRlcwpgYGB7cn0KIyBTZXQgc2VlZApzZXQuc2VlZCgxMjM0NSkKIyBBZGRpbiBjb3ZhcmlhdGVzCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBTZXQgdXAgbmV3IGRhdGFmcmFtZQpMb25nX2RhdGFfbmV3IDwtIG1ldGFfY291bnRzCgoKIyBMb29wIHJ1bm5pbmcgdGhlIExNIHRvIGdldCBuZXcgdmFyaWFibGVzIHdpdGggZXJyb3IgdGhhdCBoYXMgYSByYW5nZSBvZiB2YWx1ZXMKIyBUYXhhIDExIC0gMTUgd2lsbCBoYXZlIFNleCBlZmZlY3QKZm9yIChpIGluIDE2OjIwKSB7CiAgZXJyb3IgPC0gcm5vcm0obnJvdyhMb25nX2RhdGFfbmV3KSwgbWVhbiA9IDEsIHNkID0gMC42KQogIExvbmdfZGF0YV9uZXdbLCBpXSA8LSBMb25nX2RhdGFfbmV3WywgaV0gKyA4ICogTG9uZ19kYXRhX25ldyRTZXggKyBlcnJvcgp9CgojIHJvdW5kIHRoZSBjb3VudHMgdG8gYnJpbmcgdGhlbSBiYWNrIHVwIHRvIDAKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyBBZGQgdGhlIG1pbmltdW0gdmFsdWUgdG8gYnJpbmcgZXZlcnl0aGluZyB1cCB0byBhdCBsZWFzdCAwCmNvdW50X3RhYmxlMSA8LSBMb25nX2RhdGFfbmV3Wyw2OjI1XQoKCiMgc2NhbGUgdG8gcG9zaXRpdmUgYW5kIG1ha2UgbGFyZ2VyCmNvdW50X3RhYmxlMSA8LSBjb3VudF90YWJsZTEgKyBhYnMobWluKGNvdW50X3RhYmxlMSkpCmNvdW50X3RhYmxlMSA8LSByb3VuZChjb3VudF90YWJsZTEqMTApCgojY2hhbmdlIExvbmdfZGF0YV9uZXcKTG9uZ19kYXRhX25ld1ssNjoyNV0gPC0gY291bnRfdGFibGUxCmBgYAoKCgpOb3cgQWRkIGluIDBzCmBgYHtyfQojIFNldCB1cCBuZXcgZGF0YWZyYW1lCnByZWRhdGFfMCA8LSBjb3VudF90YWJsZTEKCiMgQWRkIHRoZSAwcyBiYWNrIGluCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCgojIFN0ZXAgMTogQ2FsY3VsYXRlIHRvdGFsIGNvdW50cyBmb3IgZWFjaCBjb2x1bW4KdG90YWxfY291bnRzIDwtIGNvbFN1bXMocHJlZGF0YV8wKQoKCiMgU3RlcCAyOiBDcmVhdGUgcHJvYmFiaWxpdHkgZ3JhZGllbnQKZ3JhZGllbnQgPC0gc2VxKDAuNSwgMC4yLCBsZW5ndGgub3V0ID0gbmNvbChwcmVkYXRhXzApKQoKIyBTdGVwIDM6IE1ha2UgdGhlIHByb2JhYmlsaXR5IGdyYWRpZW50IGludmVyc2UgdG8gdG90YWwgY291bnRzIChpZSBoaWdoZXIgdG90YWwgdmFsdWUsIGxvd2VyIHByb3BvcnRpb24gb2YgMHMpCnRvdGFsX2NvdW50cyA8LSB0b3RhbF9jb3VudHNbb3JkZXIodG90YWxfY291bnRzKV0KZ3JhZGllbnQgPC0gZ3JhZGllbnRbb3JkZXIoLWdyYWRpZW50KV0KCiMgU3RlcCA0ICYgNTogR2VuZXJhdGUgcmFuZG9tIG51bWJlcnMgYW5kIHNldCBjb3VudHMgdG8gMCBiYXNlZCBvbiBwcm9iYWJpbGl0eSBncmFkaWVudAoKZm9yIChpIGluIHNlcV9hbG9uZyh0b3RhbF9jb3VudHMpKSB7CiAgcHJvYiA8LSBncmFkaWVudFtpXQogICMgQ2FsY3VsYXRlIG51bWJlciBvZiAwcyB0byBhZGQgYmFzZWQgb24gcHJvYmFiaWxpdHkKICBudW1femVyb3MgPC0gc3VtKHJ1bmlmKG5yb3cocHJlZGF0YV8wKSkgPD0gcHJvYikKICAjIFJhbmRvbWx5IHNlbGVjdCByb3dzIHRvIHNldCB0byAwCiAgIyBTZXQgc2VlZAogIHNldC5zZWVkKDEyMzQ1K2kpCiAgcm93c190b196ZXJvIDwtIHNhbXBsZShucm93KHByZWRhdGFfMCksIG51bV96ZXJvcykKICAjIFNldCBjb3VudHMgdG8gMAogIHByZWRhdGFfMFtyb3dzX3RvX3plcm8sIGldIDwtIDAKfQoKIyBtZXJnZSB3aXRoIG1ldGFkYXRhIGZvciBwbG90dGluZwp6ZXJvX2RhdGExIDwtIG1lcmdlKG1ldGFfZGF0YSwgcHJlZGF0YV8wLCBieSA9IDApCnplcm9fZGF0YTEgPC0gY29sdW1uX3RvX3Jvd25hbWVzKHplcm9fZGF0YTEsICJSb3cubmFtZXMiKQojcm91bmQgdGhlIGNvdW50cwp6ZXJvX2RhdGExWyw2OjI1XSA8LSByb3VuZCh6ZXJvX2RhdGExWyw2OjI1XSkKYGBgCgpHcmFwaHMgdG8gQ2hlY2sKYGBge3J9CiMgSW5kaXZpZHVhbCBTcGVjaWVzIFBsb3RzCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgUGl2b3QgdG8gbG9uZyBkYXRhCmNvdW50X2xvbmcgPC0gdGlkeXI6OnBpdm90X2xvbmdlcih6ZXJvX2RhdGExLCBjb2xzID0gc3RhcnRzX3dpdGgoInNwIiksIG5hbWVzX3RvID0gIlNwZWNpZXMiKQoKIyBQbG90IHRoZSBkYXRhCmNvdW50X2xvbmcgJT4lCiAgZ2dwbG90KGFlcyh4ID0gVGltZSwgeSA9IHZhbHVlLCBjb2xvdXIgPSBhcy5mYWN0b3IoSUQpLAogICAgICAgICAgICAgZ3JvdXAgPSBhcy5mYWN0b3IoSUQpLCBsaW5ldHlwZSA9IGFzLmZhY3RvcihJRCkpKSArCiAgZ2VvbV9saW5lKCkgKyAKICBnZW9tX3BvaW50KCkgKwogIGdlb21faml0dGVyKCkgKwogIHlsYWIoIkNvdW50IikgKwogIGxhYnMobGluZXR5cGUgPSAiSUQiLCBjb2xvciA9ICJJRCIpICsKICBmYWNldF93cmFwKH4gU3BlY2llcykgKyAgIyBDcmVhdGUgYSBwYW5lbCBmb3IgZWFjaCBzcGVjaWVzCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgZ2d0aXRsZSgiVGltZSBTZXJpZXMgb2YgTj0yMCwgMHMiKQoKCiMgRGlzdHJpYnV0aW9uIG9mIGNvdW50cwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpoaXN0KGFzLm1hdHJpeCh6ZXJvX2RhdGExWyw2OjI1XSksIGJyZWFrcyA9IDEwMCwgbWFpbiA9ICJEaXN0cmlidXRpb24gb2YgR0xWIERhdGEiLCB4bGFiID0gIkNvdW50cyIpCgojIENvcnJlbGF0aW9uIG1hdHJpeApjb3JfcmF3MSA8LSBjb3IoKHplcm9fZGF0YTFbLDY6MjVdKSwgbWV0aG9kID0gInNwZWFybWFuIikKaGVhdG1hcChjb3JfcmF3MSwgQ29sdiA9IE5BLCBSb3d2ID0gTkEsIG1haW4gPSAiQ29ycmVsYXRpb24gb2YgMCBpbmZsYXRlZCBubyBjb3ZhcmlhdGVzIikKYGBgCgoKU2F2ZSB0aGUgQ291bnRzCmBgYHtyfQp3cml0ZS5jc3YobWV0YV9jb3VudHMsIGhlcmUoIkRhdGEiLCJHTFZfU2ltRGF0YSIsICJEYXRhc2V0XzMiLCAiR0xWX04yMC5jc3YiKSkKd3JpdGUuY3N2KExvbmdfZGF0YV9uZXcsIGhlcmUoIkRhdGEiLCJHTFZfU2ltRGF0YSIsICJEYXRhc2V0XzMiLCJHTFZfQ292X04yMC5jc3YiKSkKd3JpdGUuY3N2KHplcm9fZGF0YTEsIGhlcmUoIkRhdGEiLCJHTFZfU2ltRGF0YSIsICJEYXRhc2V0XzMiLCJHTFZfQ292WmVyb19OMjAuY3N2IikpCmBgYAoKCiMgNC4gU2ltdWxhdGUgTiA9IDUwCioqKiAKX19TaW11bGF0ZSBDb3VudHNfXyAgClNpbXVsYXRlIEdMViBmb3IgNTAgaW5kaXZpZHVhbHMsIDUwIHNwZWNpZXMsIDEwIHRpbWVwb2ludHMsIGRlbnNlIG4KYGBge3J9CiMgU2V0IHNlZWQKc2V0LnNlZWQoMTIzNDUpCgojIFN0ZXAgMSBSdW4gR0xWIGZvciBuIG51bWJlciBvZiBzdWJqZWN0IGFuZCB0aW1lcG9pbnRzCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiMgR2VuZXJhdGUgaW50ZXJhY3Rpb25zIGZyb20gdW5pZm9ybSBkaXN0cmlidXRpb24KQV91bmlmb3JtIDwtIHJhbmRvbUEoCiAgICBuX3NwZWNpZXMgPSA1MCwKICAgIGRpYWdvbmFsID0gLTEuMCwKICAgIGNvbm5lY3RhbmNlID0gMC45KQoKIyBDcmVhdGUgYW4gZW1wdHkgbGlzdCB0byBzdG9yZSB0aGUgY291bnQgdGFibGVzIGZvciBlYWNoIHN1YmplY3QKY291bnRfdGFibGVzIDwtIGxpc3QoKQoKCiMgTG9vcCB0aHJvdWdoIDUwIHN1YmplY3RzIGFuZCBnZW5lcmF0ZSBjb3VudCB0YWJsZXMgZm9yIGVhY2gKZm9yIChpIGluIDE6NTApIHsKICAjIFNldCB0aGUgc2VlZCBmb3IgZWFjaCBzdWJqZWN0CiAgc2V0LnNlZWQoMTIzNDUgKyBpKSAgCiAjIEdlbmVyYWxpemVkIExvdGthLVZvbHRlcnJhIChnTFYpCiAgdHNlX2dsdiA8LSBzaW11bGF0ZUdMVihuX3NwZWNpZXMgPSA1MCwKICAgICAgICAgICAgICAgICAgICAgICBBID0gQV91bmlmb3JtLAogICAgICAgICAgICAgICAgICAgICAgIHRfc3RhcnQgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICB0X3N0b3JlID0gMTAsCiAgICAgICAgICAgICAgICAgICAgICAgc3RvY2hhc3RpYyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgIG5vcm0gPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICBlcnJvcl92YXJpYW5jZSA9IDAuMDEpCiAgCiAgIyBHZXQgdGhlIGNvdW50IHRhYmxlCiAgc2ltX2RhdGEgPC0gdHNlX2dsdkBhc3NheXNAZGF0YUBsaXN0RGF0YVtbImNvdW50cyJdXQogIAogICMgU3RvcmUgdGhlIGNvdW50IHRhYmxlIGluIHRoZSBsaXN0CiAgY291bnRfdGFibGVzW1tpXV0gPC0gdChzaW1fZGF0YSkKfQoKIyBTdGVwIDIgLSBNZXJnZSB0b2dldGhlcgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgQ29tYmluZSBhbGwgY291bnQgdGFibGVzIGludG8gb25lIGRhdGEgZnJhbWUKY29tYmluZWRfY291bnRfdGFibGUgPC0gZG8uY2FsbChyYmluZCwgY291bnRfdGFibGVzKQoKIyBSZW5hbWUgdGhlIHJvd25hbWVzIGJhc2VkIG9uIHRoZSBjb3VudCB0YWJsZSBudW1iZXIKcm93bmFtZXMoY29tYmluZWRfY291bnRfdGFibGUpIDwtIHBhc3RlMCgiU2JqIiwgcmVwKDE6NTAsIGVhY2ggPSBucm93KGNvdW50X3RhYmxlc1tbMV1dKSksICJfVGltZSIsIDE6MTApCgpgYGAKCgpfX0NyZWF0ZSBGYWtlIE1ldGFkYXRhX18gIAoxLiBTZXggKE0gb3IgRiwgNTAvNTAgUmF0aW8pCjIuIEFnZSAtIHNhbXBsZSBmcm9tIGJldHdlZW4gMTggYW5kIDQ1CjMuIEJNSSAtIHNhbXBsZSBiZXR3ZWVuIDE4IGFuZCAzNQoKTWFrZSBNZXRhZGF0YSBhbmQgbWVyZ2Ugd2l0aCB0aGUgY291bnQgZGF0YQpgYGB7cn0KIyBTZXQgc2VlZApzZXQuc2VlZCgxMjM0NSkKIyBEZiAxIGlzIE1ldGFkYXRhCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCm1ldGFfZGF0YSA8LSAgZXhwYW5kLmdyaWQoVGltZSA9IDE6MTAsSUQgPSAxOjUwKQpyb3duYW1lcyhtZXRhX2RhdGEpIDwtIHJvd25hbWVzKGNvbWJpbmVkX2NvdW50X3RhYmxlKQojIFNldCBzZWVkCnNldC5zZWVkKDEyMzQ1KQptZXRhX2RhdGEkU2V4IDwtIHJlcChjKDAsIDEpLCBlYWNoID0gNTApCiMgU2V0IHNlZWQKc2V0LnNlZWQoMTIzNDUpCm1ldGFfZGF0YSRBZ2UgPC0gcmVwKHNhbXBsZSgxODo0NSwgNTAsIHJlcGxhY2UgPSBUUlVFKSwgZWFjaCA9IDEwKQojIFNldCBzZWVkCnNldC5zZWVkKDEyMzQ1KQptZXRhX2RhdGEkQk1JIDwtIHJlcChzYW1wbGUoMTg6MzUsIDUwLCByZXBsYWNlID0gVFJVRSksIGVhY2ggPSAxMCkKCiMgQ2VudGVyIHRoZSBjb250aW51b3VzIHZhcmlhYmxlcwptZXRhX2RhdGEkQWdlIDwtIG1ldGFfZGF0YSRBZ2UgLSBtZWFuKG1ldGFfZGF0YSRBZ2UpCm1ldGFfZGF0YSRCTUkgPC0gbWV0YV9kYXRhJEJNSSAtIG1lYW4obWV0YV9kYXRhJEJNSSkKCgojIERmIDIgaXMgTWV0YWRhdGEgbWVyZ2VkIHdpdGggQ291bnRzCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiNSb3VuZCBvZmYgYW5kIGluY3JlYXNlCmNvbWJpbmVkX2NvdW50X3RhYmxlIDwtIGFzLmRhdGEuZnJhbWUoY29tYmluZWRfY291bnRfdGFibGUgKyBhYnMobWluKGNvbWJpbmVkX2NvdW50X3RhYmxlKSkpCmNvbWJpbmVkX2NvdW50X3RhYmxlIDwtIChjb21iaW5lZF9jb3VudF90YWJsZSkqMTAKbWV0YV9jb3VudHMgPC0gYmFzZTo6bWVyZ2UobWV0YV9kYXRhLCBjb21iaW5lZF9jb3VudF90YWJsZSwgYnkgPSJyb3cubmFtZXMiLCBhbGwgPSBUUlVFKQptZXRhX2NvdW50cyA8LSBjb2x1bW5fdG9fcm93bmFtZXMobWV0YV9jb3VudHMsICJSb3cubmFtZXMiKQoKCmBgYAoKCkFkZCBpbiBiaW9sb2dpY2FsIGNvdmFyaWF0ZXMKYGBge3J9CiMgU2V0IHNlZWQKc2V0LnNlZWQoMTIzNDUpCiMgQWRkaW4gY292YXJpYXRlcwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgU2V0IHVwIG5ldyBkYXRhZnJhbWUKTG9uZ19kYXRhX25ldyA8LSBtZXRhX2NvdW50cwoKCiMgVGF4YSAyMSAtIDMwIHdpbGwgaGF2ZSBTZXggZWZmZWN0CmZvciAoaSBpbiAyNjozNSkgewogIGVycm9yIDwtIHJub3JtKG5yb3coTG9uZ19kYXRhX25ldyksIG1lYW4gPSAxLCBzZCA9IDAuNikKICBMb25nX2RhdGFfbmV3WywgaV0gPC0gTG9uZ19kYXRhX25ld1ssIGldICsgOCAqIExvbmdfZGF0YV9uZXckU2V4ICsgZXJyb3IKfQoKIyByb3VuZCB0aGUgY291bnRzIHRvIGJyaW5nIHRoZW0gYmFjayB1cCB0byAwCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiMgQWRkIHRoZSBtaW5pbXVtIHZhbHVlIHRvIGJyaW5nIGV2ZXJ5dGhpbmcgdXAgdG8gYXQgbGVhc3QgMApjb3VudF90YWJsZTEgPC0gTG9uZ19kYXRhX25ld1ssNjo1NV0KCgojIHNjYWxlIHRvIHBvc2l0aXZlIGFuZCBtYWtlIGxhcmdlcgpjb3VudF90YWJsZTEgPC0gY291bnRfdGFibGUxICsgYWJzKG1pbihjb3VudF90YWJsZTEpKQpjb3VudF90YWJsZTEgPC0gcm91bmQoY291bnRfdGFibGUxKjEwKQoKI2NoYW5nZSBMb25nX2RhdGFfbmV3CkxvbmdfZGF0YV9uZXdbLDY6NTVdIDwtIGNvdW50X3RhYmxlMQpgYGAKCgoKTm93IEFkZCBpbiAwcwpgYGB7cn0KIyBTZXQgdXAgbmV3IGRhdGFmcmFtZQpwcmVkYXRhXzAgPC0gY291bnRfdGFibGUxCgojIEFkZCB0aGUgMHMgYmFjayBpbgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgoKIyBTdGVwIDE6IENhbGN1bGF0ZSB0b3RhbCBjb3VudHMgZm9yIGVhY2ggY29sdW1uCnRvdGFsX2NvdW50cyA8LSBjb2xTdW1zKHByZWRhdGFfMCkKCgojIFN0ZXAgMjogQ3JlYXRlIHByb2JhYmlsaXR5IGdyYWRpZW50CmdyYWRpZW50IDwtIHNlcSgwLjUsIDAuMiwgbGVuZ3RoLm91dCA9IG5jb2wocHJlZGF0YV8wKSkKCiMgU3RlcCAzOiBNYWtlIHRoZSBwcm9iYWJpbGl0eSBncmFkaWVudCBpbnZlcnNlIHRvIHRvdGFsIGNvdW50cyAoaWUgaGlnaGVyIHRvdGFsIHZhbHVlLCBsb3dlciBwcm9wb3J0aW9uIG9mIDBzKQp0b3RhbF9jb3VudHMgPC0gdG90YWxfY291bnRzW29yZGVyKHRvdGFsX2NvdW50cyldCmdyYWRpZW50IDwtIGdyYWRpZW50W29yZGVyKC1ncmFkaWVudCldCgojIFN0ZXAgNCAmIDU6IEdlbmVyYXRlIHJhbmRvbSBudW1iZXJzIGFuZCBzZXQgY291bnRzIHRvIDAgYmFzZWQgb24gcHJvYmFiaWxpdHkgZ3JhZGllbnQKCmZvciAoaSBpbiBzZXFfYWxvbmcodG90YWxfY291bnRzKSkgewogIHByb2IgPC0gZ3JhZGllbnRbaV0KICAjIENhbGN1bGF0ZSBudW1iZXIgb2YgMHMgdG8gYWRkIGJhc2VkIG9uIHByb2JhYmlsaXR5CiAgbnVtX3plcm9zIDwtIHN1bShydW5pZihucm93KHByZWRhdGFfMCkpIDw9IHByb2IpCiAgIyBSYW5kb21seSBzZWxlY3Qgcm93cyB0byBzZXQgdG8gMAogICMgU2V0IHNlZWQKICBzZXQuc2VlZCgxMjM0NStpKQogIHJvd3NfdG9femVybyA8LSBzYW1wbGUobnJvdyhwcmVkYXRhXzApLCBudW1femVyb3MpCiAgIyBTZXQgY291bnRzIHRvIDAKICBwcmVkYXRhXzBbcm93c190b196ZXJvLCBpXSA8LSAwCn0KCiMgbWVyZ2Ugd2l0aCBtZXRhZGF0YSBmb3IgcGxvdHRpbmcKemVyb19kYXRhMSA8LSBtZXJnZShtZXRhX2RhdGEsIHByZWRhdGFfMCwgYnkgPSAwKQp6ZXJvX2RhdGExIDwtIGNvbHVtbl90b19yb3duYW1lcyh6ZXJvX2RhdGExLCAiUm93Lm5hbWVzIikKI3JvdW5kIHRoZSBjb3VudHMKemVyb19kYXRhMVssNjo1NV0gPC0gcm91bmQoemVyb19kYXRhMVssNjo1NV0pCmBgYAoKR3JhcGhzIHRvIENoZWNrCmBgYHtyfQojIEluZGl2aWR1YWwgU3BlY2llcyBQbG90cwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIFBpdm90IHRvIGxvbmcgZGF0YQpjb3VudF9sb25nIDwtIHRpZHlyOjpwaXZvdF9sb25nZXIoemVyb19kYXRhMSwgY29scyA9IHN0YXJ0c193aXRoKCJzcCIpLCBuYW1lc190byA9ICJTcGVjaWVzIikKCiMgUGxvdCB0aGUgZGF0YQpjb3VudF9sb25nICU+JQogIGdncGxvdChhZXMoeCA9IFRpbWUsIHkgPSB2YWx1ZSwgY29sb3VyID0gYXMuZmFjdG9yKElEKSwKICAgICAgICAgICAgIGdyb3VwID0gYXMuZmFjdG9yKElEKSwgbGluZXR5cGUgPSBhcy5mYWN0b3IoSUQpKSkgKwogIGdlb21fbGluZSgpICsgCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2ppdHRlcigpICsKICB5bGFiKCJDb3VudCIpICsKICBsYWJzKGxpbmV0eXBlID0gIklEIiwgY29sb3IgPSAiSUQiKSArCiAgZmFjZXRfd3JhcCh+IFNwZWNpZXMpICsgICMgQ3JlYXRlIGEgcGFuZWwgZm9yIGVhY2ggc3BlY2llcwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGdndGl0bGUoIlRpbWUgU2VyaWVzIG9mIE49NTAsIDBzIikKCgojIERpc3RyaWJ1dGlvbiBvZiBjb3VudHMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKaGlzdChhcy5tYXRyaXgoemVyb19kYXRhMVssNjo1NV0pLCBicmVha3MgPSAxMDAsIG1haW4gPSAiRGlzdHJpYnV0aW9uIG9mIEdMViBEYXRhIiwgeGxhYiA9ICJDb3VudHMiKQoKIyBDb3JyZWxhdGlvbiBtYXRyaXgKY29yX3JhdzEgPC0gY29yKCh6ZXJvX2RhdGExWyw2OjU1XSksIG1ldGhvZCA9ICJzcGVhcm1hbiIpCmhlYXRtYXAoY29yX3JhdzEsIENvbHYgPSBOQSwgUm93diA9IE5BLCBtYWluID0gIkNvcnJlbGF0aW9uIG9mIDAgaW5mbGF0ZWQgbm8gY292YXJpYXRlcyIpCmBgYAoKClNhdmUgdGhlIENvdW50cwpgYGB7cn0Kd3JpdGUuY3N2KG1ldGFfY291bnRzLCBoZXJlKCJEYXRhIiwiR0xWX1NpbURhdGEiLCAiRGF0YXNldF8zIiwiR0xWX041MC5jc3YiKSkKd3JpdGUuY3N2KExvbmdfZGF0YV9uZXcsIGhlcmUoIkRhdGEiLCJHTFZfU2ltRGF0YSIsICJEYXRhc2V0XzMiLCJHTFZfQ292X041MC5jc3YiKSkKd3JpdGUuY3N2KHplcm9fZGF0YTEsIGhlcmUoIkRhdGEiLCJHTFZfU2ltRGF0YSIsICJEYXRhc2V0XzMiLCJHTFZfQ292WmVyb19ONTAuY3N2IikpCmBgYAoKCgojIDUuIFNpbXVsYXRlIE4gPSA3NQoqKiogCl9fU2ltdWxhdGUgQ291bnRzX18gIApTaW11bGF0ZSBHTFYgZm9yIDc1IHNwZWNpZXMsIDUwIGluZGl2aWR1YWxzLCAxMCB0aW1lcG9pbnRzLCBkZW5zZSBuCmBgYHtyfQojIFNldCBzZWVkCnNldC5zZWVkKDEyMzQ1KQoKIyBTdGVwIDEgUnVuIEdMViBmb3IgbiBudW1iZXIgb2Ygc3ViamVjdCBhbmQgdGltZXBvaW50cwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIEdlbmVyYXRlIGludGVyYWN0aW9ucyBmcm9tIHVuaWZvcm0gZGlzdHJpYnV0aW9uCkFfdW5pZm9ybSA8LSByYW5kb21BKAogICAgbl9zcGVjaWVzID0gNzUsCiAgICBkaWFnb25hbCA9IC0xLjAsCiAgICBjb25uZWN0YW5jZSA9IDAuOSkKCiMgQ3JlYXRlIGFuIGVtcHR5IGxpc3QgdG8gc3RvcmUgdGhlIGNvdW50IHRhYmxlcyBmb3IgZWFjaCBzdWJqZWN0CmNvdW50X3RhYmxlcyA8LSBsaXN0KCkKCgojIExvb3AgdGhyb3VnaCA1MCBzdWJqZWN0cyBhbmQgZ2VuZXJhdGUgY291bnQgdGFibGVzIGZvciBlYWNoCmZvciAoaSBpbiAxOjUwKSB7CiAgIyBTZXQgdGhlIHNlZWQgZm9yIGVhY2ggc3ViamVjdAogIHNldC5zZWVkKDEyMzQ1ICsgaSkgIAogIyBHZW5lcmFsaXplZCBMb3RrYS1Wb2x0ZXJyYSAoZ0xWKQogIHRzZV9nbHYgPC0gc2ltdWxhdGVHTFYobl9zcGVjaWVzID0gNzUsCiAgICAgICAgICAgICAgICAgICAgICAgQSA9IEFfdW5pZm9ybSwKICAgICAgICAgICAgICAgICAgICAgICB0X3N0YXJ0ID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgdF9zdG9yZSA9IDEwLAogICAgICAgICAgICAgICAgICAgICAgIHN0b2NoYXN0aWMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICBub3JtID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JfdmFyaWFuY2UgPSAwLjAxKQogIAogICMgR2V0IHRoZSBjb3VudCB0YWJsZQogIHNpbV9kYXRhIDwtIHRzZV9nbHZAYXNzYXlzQGRhdGFAbGlzdERhdGFbWyJjb3VudHMiXV0KICAKICAjIFN0b3JlIHRoZSBjb3VudCB0YWJsZSBpbiB0aGUgbGlzdAogIGNvdW50X3RhYmxlc1tbaV1dIDwtIHQoc2ltX2RhdGEpCn0KCiMgU3RlcCAyIC0gTWVyZ2UgdG9nZXRoZXIKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIENvbWJpbmUgYWxsIGNvdW50IHRhYmxlcyBpbnRvIG9uZSBkYXRhIGZyYW1lCmNvbWJpbmVkX2NvdW50X3RhYmxlIDwtIGRvLmNhbGwocmJpbmQsIGNvdW50X3RhYmxlcykKCiMgUmVuYW1lIHRoZSByb3duYW1lcyBiYXNlZCBvbiB0aGUgY291bnQgdGFibGUgbnVtYmVyCnJvd25hbWVzKGNvbWJpbmVkX2NvdW50X3RhYmxlKSA8LSBwYXN0ZTAoIlNiaiIsIHJlcCgxOjUwLCBlYWNoID0gbnJvdyhjb3VudF90YWJsZXNbWzFdXSkpLCAiX1RpbWUiLCAxOjEwKQoKYGBgCgoKX19DcmVhdGUgRmFrZSBNZXRhZGF0YV9fICAKMS4gU2V4IChNIG9yIEYsIDUwLzUwIFJhdGlvKQoyLiBBZ2UgLSBzYW1wbGUgZnJvbSBiZXR3ZWVuIDE4IGFuZCA0NQozLiBCTUkgLSBzYW1wbGUgYmV0d2VlbiAxOCBhbmQgMzUKCk1ha2UgTWV0YWRhdGEgYW5kIG1lcmdlIHdpdGggdGhlIGNvdW50IGRhdGEKYGBge3J9CiMgU2V0IHNlZWQKc2V0LnNlZWQoMTIzNDUpCiMgRGYgMSBpcyBNZXRhZGF0YQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwptZXRhX2RhdGEgPC0gIGV4cGFuZC5ncmlkKFRpbWUgPSAxOjEwLElEID0gMTo1MCkKcm93bmFtZXMobWV0YV9kYXRhKSA8LSByb3duYW1lcyhjb21iaW5lZF9jb3VudF90YWJsZSkKIyBTZXQgc2VlZApzZXQuc2VlZCgxMjM0NSkKbWV0YV9kYXRhJFNleCA8LSByZXAoYygwLCAxKSwgZWFjaCA9IDUwKQojIFNldCBzZWVkCnNldC5zZWVkKDEyMzQ1KQptZXRhX2RhdGEkQWdlIDwtIHJlcChzYW1wbGUoMTg6NDUsIDUwLCByZXBsYWNlID0gVFJVRSksIGVhY2ggPSAxMCkKIyBTZXQgc2VlZApzZXQuc2VlZCgxMjM0NSkKbWV0YV9kYXRhJEJNSSA8LSByZXAoc2FtcGxlKDE4OjM1LCA1MCwgcmVwbGFjZSA9IFRSVUUpLCBlYWNoID0gMTApCgojIENlbnRlciB0aGUgY29udGludW91cyB2YXJpYWJsZXMKbWV0YV9kYXRhJEFnZSA8LSBtZXRhX2RhdGEkQWdlIC0gbWVhbihtZXRhX2RhdGEkQWdlKQptZXRhX2RhdGEkQk1JIDwtIG1ldGFfZGF0YSRCTUkgLSBtZWFuKG1ldGFfZGF0YSRCTUkpCgoKIyBEZiAyIGlzIE1ldGFkYXRhIG1lcmdlZCB3aXRoIENvdW50cwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojUm91bmQgb2ZmIGFuZCBpbmNyZWFzZQpjb21iaW5lZF9jb3VudF90YWJsZSA8LSBhcy5kYXRhLmZyYW1lKGNvbWJpbmVkX2NvdW50X3RhYmxlICsgYWJzKG1pbihjb21iaW5lZF9jb3VudF90YWJsZSkpKQpjb21iaW5lZF9jb3VudF90YWJsZSA8LSAoY29tYmluZWRfY291bnRfdGFibGUpKjEwCm1ldGFfY291bnRzIDwtIGJhc2U6Om1lcmdlKG1ldGFfZGF0YSwgY29tYmluZWRfY291bnRfdGFibGUsIGJ5ID0icm93Lm5hbWVzIiwgYWxsID0gVFJVRSkKbWV0YV9jb3VudHMgPC0gY29sdW1uX3RvX3Jvd25hbWVzKG1ldGFfY291bnRzLCAiUm93Lm5hbWVzIikKCgpgYGAKCgpBZGQgaW4gYmlvbG9naWNhbCBjb3ZhcmlhdGVzCmBgYHtyfQojIFNldCBzZWVkCnNldC5zZWVkKDEyMzQ1KQojIEFkZGluIGNvdmFyaWF0ZXMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIFNldCB1cCBuZXcgZGF0YWZyYW1lCkxvbmdfZGF0YV9uZXcgPC0gbWV0YV9jb3VudHMKCgojIExvb3AgcnVubmluZyB0aGUgTE0gdG8gZ2V0IG5ldyB2YXJpYWJsZXMgd2l0aCBlcnJvciB0aGF0IGhhcyBhIHJhbmdlIG9mIHZhbHVlcwoKIyBUYXhhIDQxIC0gNjAgd2lsbCBoYXZlIFNleCBlZmZlY3QKZm9yIChpIGluIDQ2OjY1KSB7CiAgZXJyb3IgPC0gcm5vcm0obnJvdyhMb25nX2RhdGFfbmV3KSwgbWVhbiA9IDEsIHNkID0gMC42KQogIExvbmdfZGF0YV9uZXdbLCBpXSA8LSBMb25nX2RhdGFfbmV3WywgaV0gKyA4ICogTG9uZ19kYXRhX25ldyRTZXggKyBlcnJvcgp9CgojIHJvdW5kIHRoZSBjb3VudHMgdG8gYnJpbmcgdGhlbSBiYWNrIHVwIHRvIDAKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyBBZGQgdGhlIG1pbmltdW0gdmFsdWUgdG8gYnJpbmcgZXZlcnl0aGluZyB1cCB0byBhdCBsZWFzdCAwCmNvdW50X3RhYmxlMSA8LSBMb25nX2RhdGFfbmV3Wyw2OjgwXQoKCiMgc2NhbGUgdG8gcG9zaXRpdmUgYW5kIG1ha2UgbGFyZ2VyCmNvdW50X3RhYmxlMSA8LSBjb3VudF90YWJsZTEgKyBhYnMobWluKGNvdW50X3RhYmxlMSkpCmNvdW50X3RhYmxlMSA8LSByb3VuZChjb3VudF90YWJsZTEqMTApCgojY2hhbmdlIExvbmdfZGF0YV9uZXcKTG9uZ19kYXRhX25ld1ssNjo4MF0gPC0gY291bnRfdGFibGUxCmBgYAoKCgpOb3cgQWRkIGluIDBzCmBgYHtyfQojIFNldCB1cCBuZXcgZGF0YWZyYW1lCnByZWRhdGFfMCA8LSBjb3VudF90YWJsZTEKCiMgQWRkIHRoZSAwcyBiYWNrIGluCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCgojIFN0ZXAgMTogQ2FsY3VsYXRlIHRvdGFsIGNvdW50cyBmb3IgZWFjaCBjb2x1bW4KdG90YWxfY291bnRzIDwtIGNvbFN1bXMocHJlZGF0YV8wKQoKCiMgU3RlcCAyOiBDcmVhdGUgcHJvYmFiaWxpdHkgZ3JhZGllbnQKZ3JhZGllbnQgPC0gc2VxKDAuNSwgMC4yLCBsZW5ndGgub3V0ID0gbmNvbChwcmVkYXRhXzApKQoKIyBTdGVwIDM6IE1ha2UgdGhlIHByb2JhYmlsaXR5IGdyYWRpZW50IGludmVyc2UgdG8gdG90YWwgY291bnRzIChpZSBoaWdoZXIgdG90YWwgdmFsdWUsIGxvd2VyIHByb3BvcnRpb24gb2YgMHMpCnRvdGFsX2NvdW50cyA8LSB0b3RhbF9jb3VudHNbb3JkZXIodG90YWxfY291bnRzKV0KZ3JhZGllbnQgPC0gZ3JhZGllbnRbb3JkZXIoLWdyYWRpZW50KV0KCiMgU3RlcCA0ICYgNTogR2VuZXJhdGUgcmFuZG9tIG51bWJlcnMgYW5kIHNldCBjb3VudHMgdG8gMCBiYXNlZCBvbiBwcm9iYWJpbGl0eSBncmFkaWVudAoKZm9yIChpIGluIHNlcV9hbG9uZyh0b3RhbF9jb3VudHMpKSB7CiAgcHJvYiA8LSBncmFkaWVudFtpXQogICMgQ2FsY3VsYXRlIG51bWJlciBvZiAwcyB0byBhZGQgYmFzZWQgb24gcHJvYmFiaWxpdHkKICBudW1femVyb3MgPC0gc3VtKHJ1bmlmKG5yb3cocHJlZGF0YV8wKSkgPD0gcHJvYikKICAjIFJhbmRvbWx5IHNlbGVjdCByb3dzIHRvIHNldCB0byAwCiAgIyBTZXQgc2VlZAogIHNldC5zZWVkKDEyMzQ1K2kpCiAgcm93c190b196ZXJvIDwtIHNhbXBsZShucm93KHByZWRhdGFfMCksIG51bV96ZXJvcykKICAjIFNldCBjb3VudHMgdG8gMAogIHByZWRhdGFfMFtyb3dzX3RvX3plcm8sIGldIDwtIDAKfQoKIyBtZXJnZSB3aXRoIG1ldGFkYXRhIGZvciBwbG90dGluZwp6ZXJvX2RhdGExIDwtIG1lcmdlKG1ldGFfZGF0YSwgcHJlZGF0YV8wLCBieSA9IDApCnplcm9fZGF0YTEgPC0gY29sdW1uX3RvX3Jvd25hbWVzKHplcm9fZGF0YTEsICJSb3cubmFtZXMiKQojcm91bmQgdGhlIGNvdW50cwp6ZXJvX2RhdGExWyw2OjgwXSA8LSByb3VuZCh6ZXJvX2RhdGExWyw2OjgwXSkKYGBgCgpHcmFwaHMgdG8gQ2hlY2sKYGBge3J9CiMgSW5kaXZpZHVhbCBTcGVjaWVzIFBsb3RzCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgUGl2b3QgdG8gbG9uZyBkYXRhCmNvdW50X2xvbmcgPC0gdGlkeXI6OnBpdm90X2xvbmdlcih6ZXJvX2RhdGExLCBjb2xzID0gc3RhcnRzX3dpdGgoInNwIiksIG5hbWVzX3RvID0gIlNwZWNpZXMiKQoKIyBQbG90IHRoZSBkYXRhCmNvdW50X2xvbmcgJT4lCiAgZ2dwbG90KGFlcyh4ID0gVGltZSwgeSA9IHZhbHVlLCBjb2xvdXIgPSBhcy5mYWN0b3IoSUQpLAogICAgICAgICAgICAgZ3JvdXAgPSBhcy5mYWN0b3IoSUQpLCBsaW5ldHlwZSA9IGFzLmZhY3RvcihJRCkpKSArCiAgZ2VvbV9saW5lKCkgKyAKICBnZW9tX3BvaW50KCkgKwogIGdlb21faml0dGVyKCkgKwogIHlsYWIoIkNvdW50IikgKwogIGxhYnMobGluZXR5cGUgPSAiSUQiLCBjb2xvciA9ICJJRCIpICsKICBmYWNldF93cmFwKH4gU3BlY2llcykgKyAgIyBDcmVhdGUgYSBwYW5lbCBmb3IgZWFjaCBzcGVjaWVzCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgZ2d0aXRsZSgiVGltZSBTZXJpZXMgb2YgTj01MCwgMHMiKQoKCiMgRGlzdHJpYnV0aW9uIG9mIGNvdW50cwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpoaXN0KGFzLm1hdHJpeCh6ZXJvX2RhdGExWyw2OjgwXSksIGJyZWFrcyA9IDEwMCwgbWFpbiA9ICJEaXN0cmlidXRpb24gb2YgR0xWIERhdGEiLCB4bGFiID0gIkNvdW50cyIpCgojIENvcnJlbGF0aW9uIG1hdHJpeApjb3JfcmF3MSA8LSBjb3IoKHplcm9fZGF0YTFbLDY6ODBdKSwgbWV0aG9kID0gInNwZWFybWFuIikKaGVhdG1hcChjb3JfcmF3MSwgQ29sdiA9IE5BLCBSb3d2ID0gTkEsIG1haW4gPSAiQ29ycmVsYXRpb24gb2YgMCBpbmZsYXRlZCBubyBjb3ZhcmlhdGVzIikKYGBgCgoKU2F2ZSB0aGUgQ291bnRzCmBgYHtyfQp3cml0ZS5jc3YobWV0YV9jb3VudHMsIGhlcmUoIkRhdGEiLCJHTFZfU2ltRGF0YSIsICJEYXRhc2V0XzMiLCJHTFZfTjc1LmNzdiIpKQp3cml0ZS5jc3YoTG9uZ19kYXRhX25ldywgaGVyZSgiRGF0YSIsIkdMVl9TaW1EYXRhIiwgIkRhdGFzZXRfMyIsIkdMVl9Db3ZfTjc1LmNzdiIpKQp3cml0ZS5jc3YoemVyb19kYXRhMSwgaGVyZSgiRGF0YSIsIkdMVl9TaW1EYXRhIiwgIkRhdGFzZXRfMyIsIkdMVl9Db3ZaZXJvX043NS5jc3YiKSkKYGBgCgoKCgoKIyA2LiBTaW11bGF0ZSBOID0gMTAwCioqKiAKCl9fU2ltdWxhdGUgQ291bnRzX18gIApTaW11bGF0ZSBHTFYgZm9yIDEwMCBzcGVjaWVzLCA1MCBpbmRpdmlkdWFscywgMTAgdGltZXBvaW50cywgZGVuc2UgbgpgYGB7cn0KIyBTZXQgc2VlZApzZXQuc2VlZCgxMjM0NSkKCiMgU3RlcCAxIFJ1biBHTFYgZm9yIG4gbnVtYmVyIG9mIHN1YmplY3QgYW5kIHRpbWVwb2ludHMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyBHZW5lcmF0ZSBpbnRlcmFjdGlvbnMgZnJvbSB1bmlmb3JtIGRpc3RyaWJ1dGlvbgpBX3VuaWZvcm0gPC0gcmFuZG9tQSgKICAgIG5fc3BlY2llcyA9IDEwMCwKICAgIGRpYWdvbmFsID0gLTEuMCwKICAgIGNvbm5lY3RhbmNlID0gMC45KQoKIyBDcmVhdGUgYW4gZW1wdHkgbGlzdCB0byBzdG9yZSB0aGUgY291bnQgdGFibGVzIGZvciBlYWNoIHN1YmplY3QKY291bnRfdGFibGVzIDwtIGxpc3QoKQoKCiMgTG9vcCB0aHJvdWdoIDUwIHN1YmplY3RzIGFuZCBnZW5lcmF0ZSBjb3VudCB0YWJsZXMgZm9yIGVhY2gKZm9yIChpIGluIDE6NTApIHsKICAjIFNldCB0aGUgc2VlZCBmb3IgZWFjaCBzdWJqZWN0CiAgc2V0LnNlZWQoMTIzNDUgKyBpKSAgCiAjIEdlbmVyYWxpemVkIExvdGthLVZvbHRlcnJhIChnTFYpCiAgdHNlX2dsdiA8LSBzaW11bGF0ZUdMVihuX3NwZWNpZXMgPSAxMDAsCiAgICAgICAgICAgICAgICAgICAgICAgQSA9IEFfdW5pZm9ybSwKICAgICAgICAgICAgICAgICAgICAgICB0X3N0YXJ0ID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgdF9zdG9yZSA9IDEwLAogICAgICAgICAgICAgICAgICAgICAgIHN0b2NoYXN0aWMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICBub3JtID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JfdmFyaWFuY2UgPSAwLjAxKQogIAogICMgR2V0IHRoZSBjb3VudCB0YWJsZQogIHNpbV9kYXRhIDwtIHRzZV9nbHZAYXNzYXlzQGRhdGFAbGlzdERhdGFbWyJjb3VudHMiXV0KICAKICAjIFN0b3JlIHRoZSBjb3VudCB0YWJsZSBpbiB0aGUgbGlzdAogIGNvdW50X3RhYmxlc1tbaV1dIDwtIHQoc2ltX2RhdGEpCn0KCiMgU3RlcCAyIC0gTWVyZ2UgdG9nZXRoZXIKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIENvbWJpbmUgYWxsIGNvdW50IHRhYmxlcyBpbnRvIG9uZSBkYXRhIGZyYW1lCmNvbWJpbmVkX2NvdW50X3RhYmxlIDwtIGRvLmNhbGwocmJpbmQsIGNvdW50X3RhYmxlcykKCiMgUmVuYW1lIHRoZSByb3duYW1lcyBiYXNlZCBvbiB0aGUgY291bnQgdGFibGUgbnVtYmVyCnJvd25hbWVzKGNvbWJpbmVkX2NvdW50X3RhYmxlKSA8LSBwYXN0ZTAoIlNiaiIsIHJlcCgxOjUwLCBlYWNoID0gbnJvdyhjb3VudF90YWJsZXNbWzFdXSkpLCAiX1RpbWUiLCAxOjEwKQoKYGBgCgoKX19DcmVhdGUgRmFrZSBNZXRhZGF0YV9fICAKMS4gU2V4IChNIG9yIEYsIDUwLzUwIFJhdGlvKQoyLiBBZ2UgLSBzYW1wbGUgZnJvbSBiZXR3ZWVuIDE4IGFuZCA0NQozLiBCTUkgLSBzYW1wbGUgYmV0d2VlbiAxOCBhbmQgMzUKCk1ha2UgTWV0YWRhdGEgYW5kIG1lcmdlIHdpdGggdGhlIGNvdW50IGRhdGEKYGBge3J9CiMgU2V0IHNlZWQKc2V0LnNlZWQoMTIzNDUpCiMgRGYgMSBpcyBNZXRhZGF0YQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwptZXRhX2RhdGEgPC0gIGV4cGFuZC5ncmlkKFRpbWUgPSAxOjEwLElEID0gMTo1MCkKcm93bmFtZXMobWV0YV9kYXRhKSA8LSByb3duYW1lcyhjb21iaW5lZF9jb3VudF90YWJsZSkKIyBTZXQgc2VlZApzZXQuc2VlZCgxMjM0NSkKbWV0YV9kYXRhJFNleCA8LSByZXAoYygwLCAxKSwgZWFjaCA9IDUwKQojIFNldCBzZWVkCnNldC5zZWVkKDEyMzQ1KQptZXRhX2RhdGEkQWdlIDwtIHJlcChzYW1wbGUoMTg6NDUsIDUwLCByZXBsYWNlID0gVFJVRSksIGVhY2ggPSAxMCkKIyBTZXQgc2VlZApzZXQuc2VlZCgxMjM0NSkKbWV0YV9kYXRhJEJNSSA8LSByZXAoc2FtcGxlKDE4OjM1LCA1MCwgcmVwbGFjZSA9IFRSVUUpLCBlYWNoID0gMTApCgojIENlbnRlciB0aGUgY29udGludW91cyB2YXJpYWJsZXMKbWV0YV9kYXRhJEFnZSA8LSBtZXRhX2RhdGEkQWdlIC0gbWVhbihtZXRhX2RhdGEkQWdlKQptZXRhX2RhdGEkQk1JIDwtIG1ldGFfZGF0YSRCTUkgLSBtZWFuKG1ldGFfZGF0YSRCTUkpCgoKIyBEZiAyIGlzIE1ldGFkYXRhIG1lcmdlZCB3aXRoIENvdW50cwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojUm91bmQgb2ZmIGFuZCBpbmNyZWFzZQpjb21iaW5lZF9jb3VudF90YWJsZSA8LSBhcy5kYXRhLmZyYW1lKGNvbWJpbmVkX2NvdW50X3RhYmxlICsgYWJzKG1pbihjb21iaW5lZF9jb3VudF90YWJsZSkpKQpjb21iaW5lZF9jb3VudF90YWJsZSA8LSAoY29tYmluZWRfY291bnRfdGFibGUpKjEwCm1ldGFfY291bnRzIDwtIGJhc2U6Om1lcmdlKG1ldGFfZGF0YSwgY29tYmluZWRfY291bnRfdGFibGUsIGJ5ID0icm93Lm5hbWVzIiwgYWxsID0gVFJVRSkKbWV0YV9jb3VudHMgPC0gY29sdW1uX3RvX3Jvd25hbWVzKG1ldGFfY291bnRzLCAiUm93Lm5hbWVzIikKCgpgYGAKCgpBZGQgaW4gYmlvbG9naWNhbCBjb3ZhcmlhdGVzCmBgYHtyfQojIFNldCBzZWVkCnNldC5zZWVkKDEyMzQ1KQojIEFkZGluIGNvdmFyaWF0ZXMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIFNldCB1cCBuZXcgZGF0YWZyYW1lCkxvbmdfZGF0YV9uZXcgPC0gbWV0YV9jb3VudHMKCgojIExvb3AgcnVubmluZyB0aGUgTE0gdG8gZ2V0IG5ldyB2YXJpYWJsZXMgd2l0aCBlcnJvciB0aGF0IGhhcyBhIHJhbmdlIG9mIHZhbHVlcwojIFRheGEgNTEgLSA3NSB3aWxsIGhhdmUgU2V4IGVmZmVjdApmb3IgKGkgaW4gNTY6ODApIHsKICBlcnJvciA8LSBybm9ybShucm93KExvbmdfZGF0YV9uZXcpLCBtZWFuID0gMSwgc2QgPSAwLjYpCiAgTG9uZ19kYXRhX25ld1ssIGldIDwtIExvbmdfZGF0YV9uZXdbLCBpXSArIDggKiBMb25nX2RhdGFfbmV3JFNleCArIGVycm9yCn0KCiMgcm91bmQgdGhlIGNvdW50cyB0byBicmluZyB0aGVtIGJhY2sgdXAgdG8gMAojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIEFkZCB0aGUgbWluaW11bSB2YWx1ZSB0byBicmluZyBldmVyeXRoaW5nIHVwIHRvIGF0IGxlYXN0IDAKY291bnRfdGFibGUxIDwtIExvbmdfZGF0YV9uZXdbLDY6MTA1XQoKCiMgc2NhbGUgdG8gcG9zaXRpdmUgYW5kIG1ha2UgbGFyZ2VyCmNvdW50X3RhYmxlMSA8LSBjb3VudF90YWJsZTEgKyBhYnMobWluKGNvdW50X3RhYmxlMSkpCmNvdW50X3RhYmxlMSA8LSByb3VuZChjb3VudF90YWJsZTEqMTApCgojY2hhbmdlIExvbmdfZGF0YV9uZXcKTG9uZ19kYXRhX25ld1ssNjoxMDVdIDwtIGNvdW50X3RhYmxlMQpgYGAKCgoKTm93IEFkZCBpbiAwcwpgYGB7cn0KIyBTZXQgdXAgbmV3IGRhdGFmcmFtZQpwcmVkYXRhXzAgPC0gY291bnRfdGFibGUxCgojIEFkZCB0aGUgMHMgYmFjayBpbgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgoKIyBTdGVwIDE6IENhbGN1bGF0ZSB0b3RhbCBjb3VudHMgZm9yIGVhY2ggY29sdW1uCnRvdGFsX2NvdW50cyA8LSBjb2xTdW1zKHByZWRhdGFfMCkKCgojIFN0ZXAgMjogQ3JlYXRlIHByb2JhYmlsaXR5IGdyYWRpZW50CmdyYWRpZW50IDwtIHNlcSgwLjUsIDAuMiwgbGVuZ3RoLm91dCA9IG5jb2wocHJlZGF0YV8wKSkKCiMgU3RlcCAzOiBNYWtlIHRoZSBwcm9iYWJpbGl0eSBncmFkaWVudCBpbnZlcnNlIHRvIHRvdGFsIGNvdW50cyAoaWUgaGlnaGVyIHRvdGFsIHZhbHVlLCBsb3dlciBwcm9wb3J0aW9uIG9mIDBzKQp0b3RhbF9jb3VudHMgPC0gdG90YWxfY291bnRzW29yZGVyKHRvdGFsX2NvdW50cyldCmdyYWRpZW50IDwtIGdyYWRpZW50W29yZGVyKC1ncmFkaWVudCldCgojIFN0ZXAgNCAmIDU6IEdlbmVyYXRlIHJhbmRvbSBudW1iZXJzIGFuZCBzZXQgY291bnRzIHRvIDAgYmFzZWQgb24gcHJvYmFiaWxpdHkgZ3JhZGllbnQKCmZvciAoaSBpbiBzZXFfYWxvbmcodG90YWxfY291bnRzKSkgewogIHByb2IgPC0gZ3JhZGllbnRbaV0KICAjIENhbGN1bGF0ZSBudW1iZXIgb2YgMHMgdG8gYWRkIGJhc2VkIG9uIHByb2JhYmlsaXR5CiAgbnVtX3plcm9zIDwtIHN1bShydW5pZihucm93KHByZWRhdGFfMCkpIDw9IHByb2IpCiAgIyBSYW5kb21seSBzZWxlY3Qgcm93cyB0byBzZXQgdG8gMAogICMgU2V0IHNlZWQKICBzZXQuc2VlZCgxMjM0NStpKQogIHJvd3NfdG9femVybyA8LSBzYW1wbGUobnJvdyhwcmVkYXRhXzApLCBudW1femVyb3MpCiAgIyBTZXQgY291bnRzIHRvIDAKICBwcmVkYXRhXzBbcm93c190b196ZXJvLCBpXSA8LSAwCn0KCiMgbWVyZ2Ugd2l0aCBtZXRhZGF0YSBmb3IgcGxvdHRpbmcKemVyb19kYXRhMSA8LSBtZXJnZShtZXRhX2RhdGEsIHByZWRhdGFfMCwgYnkgPSAwKQp6ZXJvX2RhdGExIDwtIGNvbHVtbl90b19yb3duYW1lcyh6ZXJvX2RhdGExLCAiUm93Lm5hbWVzIikKI3JvdW5kIHRoZSBjb3VudHMKemVyb19kYXRhMVssNjoxMDVdIDwtIHJvdW5kKHplcm9fZGF0YTFbLDY6MTA1XSkKYGBgCgpHcmFwaHMgdG8gQ2hlY2sKYGBge3J9CiMgSW5kaXZpZHVhbCBTcGVjaWVzIFBsb3RzCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgUGl2b3QgdG8gbG9uZyBkYXRhCmNvdW50X2xvbmcgPC0gdGlkeXI6OnBpdm90X2xvbmdlcih6ZXJvX2RhdGExLCBjb2xzID0gc3RhcnRzX3dpdGgoInNwIiksIG5hbWVzX3RvID0gIlNwZWNpZXMiKQoKIyBQbG90IHRoZSBkYXRhCmNvdW50X2xvbmcgJT4lCiAgZ2dwbG90KGFlcyh4ID0gVGltZSwgeSA9IHZhbHVlLCBjb2xvdXIgPSBhcy5mYWN0b3IoSUQpLAogICAgICAgICAgICAgZ3JvdXAgPSBhcy5mYWN0b3IoSUQpLCBsaW5ldHlwZSA9IGFzLmZhY3RvcihJRCkpKSArCiAgZ2VvbV9saW5lKCkgKyAKICBnZW9tX3BvaW50KCkgKwogIGdlb21faml0dGVyKCkgKwogIHlsYWIoIkNvdW50IikgKwogIGxhYnMobGluZXR5cGUgPSAiSUQiLCBjb2xvciA9ICJJRCIpICsKICBmYWNldF93cmFwKH4gU3BlY2llcykgKyAgIyBDcmVhdGUgYSBwYW5lbCBmb3IgZWFjaCBzcGVjaWVzCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgZ2d0aXRsZSgiVGltZSBTZXJpZXMgb2YgTj0xMDAsIDBzIikKCgojIERpc3RyaWJ1dGlvbiBvZiBjb3VudHMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKaGlzdChhcy5tYXRyaXgoemVyb19kYXRhMVssNjoxMDVdKSwgYnJlYWtzID0gMTAwLCBtYWluID0gIkRpc3RyaWJ1dGlvbiBvZiBHTFYgRGF0YSIsIHhsYWIgPSAiQ291bnRzIikKCiMgQ29ycmVsYXRpb24gbWF0cml4CmNvcl9yYXcxIDwtIGNvcigoemVyb19kYXRhMVssNjoxMDVdKSwgbWV0aG9kID0gInNwZWFybWFuIikKaGVhdG1hcChjb3JfcmF3MSwgQ29sdiA9IE5BLCBSb3d2ID0gTkEsIG1haW4gPSAiQ29ycmVsYXRpb24gb2YgMCBpbmZsYXRlZCBubyBjb3ZhcmlhdGVzIikKYGBgCgoKU2F2ZSB0aGUgQ291bnRzCmBgYHtyfQp3cml0ZS5jc3YobWV0YV9jb3VudHMsIGhlcmUoIkRhdGEiLCJHTFZfU2ltRGF0YSIsICJEYXRhc2V0XzMiLCJHTFZfTjEwMC5jc3YiKSkKd3JpdGUuY3N2KExvbmdfZGF0YV9uZXcsIGhlcmUoIkRhdGEiLCJHTFZfU2ltRGF0YSIsICJEYXRhc2V0XzMiLCJHTFZfQ292X04xMDAuY3N2IikpCndyaXRlLmNzdih6ZXJvX2RhdGExLCBoZXJlKCJEYXRhIiwiR0xWX1NpbURhdGEiLCAiRGF0YXNldF8zIiwiR0xWX0Nvdlplcm9fTjEwMC5jc3YiKSkKYGBgCgoKCgoKCgo=